diff --git a/include/cangjie/Macro/NodeSerialization.h b/include/cangjie/Macro/NodeSerialization.h index 59e42c1d..8781b05f 100644 --- a/include/cangjie/Macro/NodeSerialization.h +++ b/include/cangjie/Macro/NodeSerialization.h @@ -14,6 +14,7 @@ #define CANGJIE_MODULES_NODESERIALIZATION_H #include +#include #include #include @@ -77,6 +78,10 @@ class NodeWriter { } uint8_t* ExportNode(); // uint8_t* -> unsafePtr in CangJie private: + using ExprSerializer = std::function; + static const ExprSerializer* FindPrimaryExprSerializer(AST::ASTKind kind); + static const ExprSerializer* FindSecondaryExprSerializer(AST::ASTKind kind); + std::vector bufferData; Ptr nodePtr = nullptr; // nodePtr is the AST node to be serialized flatbuffers::Offset emptyDeclBase = flatbuffers::Offset(); @@ -119,6 +124,7 @@ class NodeWriter { flatbuffers::Offset SerializeLitConstExpr(AstExpr expr); flatbuffers::Offset SerializeUnaryExpr(AstExpr expr); flatbuffers::Offset SerializeParenExpr(AstExpr expr); + flatbuffers::Offset SerializeAmbiguousForcedCastExpr(AstExpr expr); flatbuffers::Offset SerializeCallExpr(const AST::Expr* expr); flatbuffers::Offset SerializeRefExpr(const AST::Expr* expr); flatbuffers::Offset SerializeReturnExpr(AstExpr expr); diff --git a/schema/NodeFormat.fbs b/schema/NodeFormat.fbs index 20f1a28f..5a3466f2 100644 --- a/schema/NodeFormat.fbs +++ b/schema/NodeFormat.fbs @@ -54,6 +54,7 @@ union AnyExpr { ARRAY_EXPR: ArrayExpr, PERFORM_EXPR: PerformExpr, RESUME_EXPR: ResumeExpr, + AMBIGUOUS_FORCED_CAST_EXPR: AmbiguousForcedCastExpr, } table MatchCase { @@ -202,6 +203,14 @@ table ParenExpr { right_paren_pos: Position; } +table AmbiguousForcedCastExpr { + base: NodeBase; + type: Type; + left_paren_pos: Position; + expr: Expr; + right_paren_pos: Position; +} + table LitConstExpr { base: NodeBase; literal: string; diff --git a/src/Macro/ExprSerialization.cpp b/src/Macro/ExprSerialization.cpp index 43a4dd6a..2b2723f1 100644 --- a/src/Macro/ExprSerialization.cpp +++ b/src/Macro/ExprSerialization.cpp @@ -94,6 +94,20 @@ flatbuffers::Offset NodeWriter::SerializeParenExpr(AstExpr exp return NodeFormat::CreateExpr(builder, fbNodeBase, NodeFormat::AnyExpr_PAREN_EXPR, fbParenExpr.Union()); } +flatbuffers::Offset NodeWriter::SerializeAmbiguousForcedCastExpr(AstExpr expr) +{ + auto forcedCastExpr = RawStaticCast(expr); + auto fbNodeBase = SerializeNodeBase(forcedCastExpr); + auto type = SerializeType(forcedCastExpr->type.get()); + auto leftParenPos = FlatPosCreateHelper(forcedCastExpr->leftParenPos); + auto operand = SerializeExpr(forcedCastExpr->rightExpr.get()); + auto rightParenPos = FlatPosCreateHelper(forcedCastExpr->rightParenPos); + auto fbForcedCastExpr = NodeFormat::CreateAmbiguousForcedCastExpr( + builder, fbNodeBase, type, &leftParenPos, operand, &rightParenPos); + return NodeFormat::CreateExpr(builder, fbNodeBase, NodeFormat::AnyExpr_AMBIGUOUS_FORCED_CAST_EXPR, + fbForcedCastExpr.Union()); +} + flatbuffers::Offset NodeWriter::SerializeFuncArg(AstFuncArg funcArg) { if (funcArg == nullptr) { @@ -632,65 +646,81 @@ flatbuffers::Offset NodeWriter::SerializeArrayExpr(AstExpr exp return NodeFormat::CreateExpr(builder, base, NodeFormat::AnyExpr_ARRAY_EXPR, fbArrayExpr.Union()); } +const NodeWriter::ExprSerializer* NodeWriter::FindPrimaryExprSerializer(AST::ASTKind kind) +{ + static std::unordered_map serializers = { + {ASTKind::WILDCARD_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeWildcardExpr(expr); }}, + {ASTKind::BINARY_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeBinaryExpr(expr); }}, + {ASTKind::LIT_CONST_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeLitConstExpr(expr); }}, + {ASTKind::UNARY_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeUnaryExpr(expr); }}, + {ASTKind::PAREN_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeParenExpr(expr); }}, + {ASTKind::AMBIGUOUS_FORCED_CAST_EXPR, + [](NodeWriter& nw, AstExpr expr) { return nw.SerializeAmbiguousForcedCastExpr(expr); }}, + {ASTKind::CALL_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeCallExpr(expr); }}, + {ASTKind::REF_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeRefExpr(expr); }}, + {ASTKind::RETURN_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeReturnExpr(expr); }}, + {ASTKind::ASSIGN_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeAssignExpr(expr); }}, + {ASTKind::MEMBER_ACCESS, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeMemberAccess(expr); }}, + {ASTKind::IF_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeIfExpr(expr); }}, + {ASTKind::BLOCK, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeBlockExpr(expr); }}, + {ASTKind::LAMBDA_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeLambdaExpr(expr); }}, + {ASTKind::TYPE_CONV_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeTypeConvExpr(expr); }}, + {ASTKind::FOR_IN_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeForInExpr(expr); }}, + {ASTKind::ARRAY_LIT, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeArrayLit(expr); }}, + {ASTKind::TUPLE_LIT, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeTupleLit(expr); }}, + {ASTKind::SUBSCRIPT_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeSubscriptExpr(expr); }}, + {ASTKind::RANGE_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeRangeExpr(expr); }}, + {ASTKind::MATCH_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeMatchExpr(expr); }}, + {ASTKind::TRY_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeTryExpr(expr); }}, + }; + auto serializer = serializers.find(kind); + return serializer == serializers.end() ? nullptr : &serializer->second; +} + +const NodeWriter::ExprSerializer* NodeWriter::FindSecondaryExprSerializer(AST::ASTKind kind) +{ + static std::unordered_map serializers = { + {ASTKind::THROW_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeThrowExpr(expr); }}, + {ASTKind::PERFORM_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializePerformExpr(expr); }}, + {ASTKind::RESUME_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeResumeExpr(expr); }}, + {ASTKind::JUMP_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeJumpExpr(expr); }}, + {ASTKind::WHILE_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeWhileExpr(expr); }}, + {ASTKind::DO_WHILE_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeDoWhileExpr(expr); }}, + {ASTKind::INC_OR_DEC_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeIncOrDecExpr(expr); }}, + {ASTKind::TOKEN_PART, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeTokenPart(expr); }}, + {ASTKind::QUOTE_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeQuoteExpr(expr); }}, + {ASTKind::IS_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeIsExpr(expr); }}, + {ASTKind::AS_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeAsExpr(expr); }}, + {ASTKind::SPAWN_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeSpawnExpr(expr); }}, + {ASTKind::SYNCHRONIZED_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeSynchronizedExpr(expr); }}, + {ASTKind::OPTIONAL_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeOptionalExpr(expr); }}, + {ASTKind::OPTIONAL_CHAIN_EXPR, + [](NodeWriter& nw, AstExpr expr) { return nw.SerializeOptionalChainExpr(expr); }}, + {ASTKind::TRAIL_CLOSURE_EXPR, + [](NodeWriter& nw, AstExpr expr) { return nw.SerializeTrailingClosureExpr(expr); }}, + {ASTKind::PRIMITIVE_TYPE_EXPR, + [](NodeWriter& nw, AstExpr expr) { return nw.SerializePrimitiveTypeExpr(expr); }}, + {ASTKind::LET_PATTERN_DESTRUCTOR, + [](NodeWriter& nw, AstExpr expr) { return nw.SerializeLetPatternDestructor(expr); }}, + {ASTKind::MACRO_EXPAND_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeMacroExpandExpr(expr); }}, + {ASTKind::ARRAY_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeArrayExpr(expr); }}, + }; + auto serializer = serializers.find(kind); + return serializer == serializers.end() ? nullptr : &serializer->second; +} + flatbuffers::Offset NodeWriter::SerializeExpr(AstExpr expr) { if (expr == nullptr) { return flatbuffers::Offset(); } - static std::unordered_map> - serializeExprMap = { - {ASTKind::WILDCARD_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeWildcardExpr(expr); }}, - {ASTKind::BINARY_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeBinaryExpr(expr); }}, - {ASTKind::LIT_CONST_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeLitConstExpr(expr); }}, - {ASTKind::UNARY_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeUnaryExpr(expr); }}, - {ASTKind::PAREN_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeParenExpr(expr); }}, - {ASTKind::CALL_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeCallExpr(expr); }}, - {ASTKind::REF_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeRefExpr(expr); }}, - {ASTKind::RETURN_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeReturnExpr(expr); }}, - {ASTKind::ASSIGN_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeAssignExpr(expr); }}, - {ASTKind::MEMBER_ACCESS, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeMemberAccess(expr); }}, - {ASTKind::IF_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeIfExpr(expr); }}, - {ASTKind::BLOCK, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeBlockExpr(expr); }}, - {ASTKind::LAMBDA_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeLambdaExpr(expr); }}, - {ASTKind::TYPE_CONV_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeTypeConvExpr(expr); }}, - {ASTKind::FOR_IN_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeForInExpr(expr); }}, - {ASTKind::ARRAY_LIT, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeArrayLit(expr); }}, - {ASTKind::TUPLE_LIT, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeTupleLit(expr); }}, - {ASTKind::SUBSCRIPT_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeSubscriptExpr(expr); }}, - {ASTKind::RANGE_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeRangeExpr(expr); }}, - {ASTKind::MATCH_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeMatchExpr(expr); }}, - {ASTKind::TRY_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeTryExpr(expr); }}, - {ASTKind::THROW_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeThrowExpr(expr); }}, - {ASTKind::PERFORM_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializePerformExpr(expr); }}, - {ASTKind::RESUME_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeResumeExpr(expr); }}, - {ASTKind::JUMP_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeJumpExpr(expr); }}, - {ASTKind::WHILE_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeWhileExpr(expr); }}, - {ASTKind::DO_WHILE_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeDoWhileExpr(expr); }}, - {ASTKind::INC_OR_DEC_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeIncOrDecExpr(expr); }}, - {ASTKind::TOKEN_PART, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeTokenPart(expr); }}, - {ASTKind::QUOTE_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeQuoteExpr(expr); }}, - {ASTKind::IS_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeIsExpr(expr); }}, - {ASTKind::AS_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeAsExpr(expr); }}, - {ASTKind::SPAWN_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeSpawnExpr(expr); }}, - {ASTKind::SYNCHRONIZED_EXPR, - [](NodeWriter& nw, AstExpr expr) { return nw.SerializeSynchronizedExpr(expr); }}, - {ASTKind::OPTIONAL_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeOptionalExpr(expr); }}, - {ASTKind::OPTIONAL_CHAIN_EXPR, - [](NodeWriter& nw, AstExpr expr) { return nw.SerializeOptionalChainExpr(expr); }}, - {ASTKind::TRAIL_CLOSURE_EXPR, - [](NodeWriter& nw, AstExpr expr) { return nw.SerializeTrailingClosureExpr(expr); }}, - {ASTKind::PRIMITIVE_TYPE_EXPR, - [](NodeWriter& nw, AstExpr expr) { return nw.SerializePrimitiveTypeExpr(expr); }}, - {ASTKind::LET_PATTERN_DESTRUCTOR, - [](NodeWriter& nw, AstExpr expr) { return nw.SerializeLetPatternDestructor(expr); }}, - {ASTKind::MACRO_EXPAND_EXPR, - [](NodeWriter& nw, AstExpr expr) { return nw.SerializeMacroExpandExpr(expr); }}, - {ASTKind::ARRAY_EXPR, [](NodeWriter& nw, AstExpr expr) { return nw.SerializeArrayExpr(expr); }}, - }; // Match ReplaceExpr func. - auto serializeFunc = serializeExprMap.find(expr->astKind); - if (serializeFunc != serializeExprMap.end()) { - return serializeFunc->second(*this, expr); + auto serializer = FindPrimaryExprSerializer(expr->astKind); + if (serializer == nullptr) { + serializer = FindSecondaryExprSerializer(expr->astKind); + } + if (serializer != nullptr) { + return (*serializer)(*this, expr); } Errorln("Expr Not Supported in Libast Yet\n"); return flatbuffers::Offset(); diff --git a/src/Macro/MacroUpdateInfo.h b/src/Macro/MacroUpdateInfo.h index a5024173..4aed0972 100644 --- a/src/Macro/MacroUpdateInfo.h +++ b/src/Macro/MacroUpdateInfo.h @@ -119,6 +119,13 @@ template <> void UpdateSingleMacroInfo(Node& curNode, Macr UpdateExpr(parent->leftExpr, parent, collector); } +template <> void UpdateSingleMacroInfo(Node& curNode, MacroCollector& collector) +{ + auto parent = StaticAs(&curNode); + UpdateExpr(parent->leftExpr, parent, collector); + UpdateExpr(parent->rightExpr, parent, collector); +} + template <> void UpdateSingleMacroInfo(Node& curNode, MacroCollector& collector) { auto parent = StaticAs(&curNode); @@ -174,4 +181,4 @@ void UpdateMacroInfo(const Ptr node, MacroCollector& collector) } -#endif \ No newline at end of file +#endif diff --git a/src/Sema/DesugarExtern.cpp b/src/Sema/DesugarExtern.cpp index 7222e13e..098868f9 100644 --- a/src/Sema/DesugarExtern.cpp +++ b/src/Sema/DesugarExtern.cpp @@ -11,7 +11,6 @@ #include "TypeCheckUtil.h" #include "cangjie/AST/Clone.h" #include "cangjie/AST/Create.h" -#include "cangjie/AST/Walker.h" namespace Cangjie { using namespace TypeCheckUtil; @@ -608,48 +607,23 @@ OwnedPtr TypeChecker::TypeCheckerImpl::BuildForcedCastCall( return call; } -// Strip cached types/desugars from a cloned subtree so the enclosing call re-checks -// it cleanly (ASTCloner copies types). -static void StripTypesForRecheck(Ptr root) -{ - Walker(root, [](Ptr n) -> VisitAction { - // Reset to the initial (unchecked) type rather than null: SetTy asserts non-null - // in debug builds, and the initial ty is what an un-type-checked node carries. - n->SetTy(Ty::GetInitialTy()); - if (auto ex = DynamicCast(n.get())) { - ex->desugarExpr = nullptr; - } - return VisitAction::WALK_CHILDREN; - }).Walk(); -} - -// Ordinary reading `U(args)` of a `(U)(args)` whose forced cast did not apply (call -// form only). When `U` is a type the operand was already synthesised as a cast probe, -// so its args are taken as freshly re-typed clones; otherwise the pristine operand is -// moved in (also the deeply nested path, where cloning would be exponential). +// Ordinary reading `U(args)` of a `(U)(args)` whose `U` does not resolve to a type +// (call form only). A type-valued `U` always selects forced-cast semantics, even when +// its operand is not Extern, so only the pristine ordinary-call operand reaches here. Ptr TypeChecker::TypeCheckerImpl::DesugarAmbiguousOrdinaryCall( - const CheckerContext& ctx, AmbiguousForcedCastExpr& afce, bool typeValid) + const CheckerContext& ctx, AmbiguousForcedCastExpr& afce) { - bool freshen = typeValid; - auto take = [freshen](OwnedPtr& e) -> OwnedPtr { - if (!freshen) { - return std::move(e); - } - auto cloned = ASTCloner::Clone(e.get()); - StripTypesForRecheck(cloned.get()); - return cloned; - }; std::vector> args; auto& operand = afce.rightExpr; if (operand->astKind == ASTKind::TUPLE_LIT) { for (auto& child : StaticAs(operand.get())->children) { - args.emplace_back(CreateFuncArg(take(child))); + args.emplace_back(CreateFuncArg(std::move(child))); } } else if (operand->astKind == ASTKind::PAREN_EXPR) { - args.emplace_back(CreateFuncArg(take(StaticAs(operand.get())->expr))); + args.emplace_back(CreateFuncArg(std::move(StaticAs(operand.get())->expr))); } else if (!(operand->astKind == ASTKind::LIT_CONST_EXPR && StaticAs(operand.get())->kind == LitConstKind::UNIT)) { - args.emplace_back(CreateFuncArg(take(operand))); + args.emplace_back(CreateFuncArg(std::move(operand))); } auto call = CreateCallExpr(std::move(afce.leftExpr), std::move(args)); CopyBasicInfo(&afce, call.get()); @@ -660,13 +634,6 @@ Ptr TypeChecker::TypeCheckerImpl::DesugarAmbiguousOrdinaryCall( afce.SetTy(ty); return ty; } - // `U(args)` did not type-check. If `U` is a type this was a malformed forced cast - // (a type-name call like `Foo(1)` fails silently here), so drop the dead call and - // report cleanly; otherwise the call already emitted its own error. - if (typeValid) { - afce.desugarExpr = nullptr; - diag.DiagnoseRefactor(DiagKindRefactor::sema_invalid_forced_cast_expr, afce); - } afce.SetTy(TypeManager::GetInvalidTy()); return TypeManager::GetInvalidTy(); } @@ -718,25 +685,23 @@ Ptr TypeChecker::TypeCheckerImpl::SynAmbiguousForcedCastExpr( return targetTy; } } + // Once `U` resolves to a type this syntax is unconditionally a forced cast. + // In particular, `(U)(args)` must not fall back to the constructor spelling + // `U(args)` when the operand is not Extern. + diag.DiagnoseRefactor(DiagKindRefactor::sema_invalid_forced_cast_expr, afce); + afce.SetTy(TypeManager::GetInvalidTy()); + return TypeManager::GetInvalidTy(); } - // Ordinary reading `U(args)` (call form only). When `U` is a type the operand - // was already synthesised above (cast probe), so its args are taken as freshly - // re-typed clones, else overload resolution silently keeps a pre-checked arg. - // When `U` is not a type the operand is pristine and moved in — also the deeply - // nested path, where cloning would be exponential (a real type only appears at - // shallow, bounded cast sites). + // Ordinary reading `U(args)` (call form only) is available only when `U` does + // not resolve to a type. The pristine operand is moved into the call. if (isCall && afce.leftExpr && afce.rightExpr) { - return DesugarAmbiguousOrdinaryCall(ctx, afce, typeValid); + return DesugarAmbiguousOrdinaryCall(ctx, afce); } - // Juxtaposition `(U)e` with no ordinary reading: a malformed forced cast when `U` - // is a type, otherwise let the operand's own diagnostics surface. - if (typeValid) { - diag.DiagnoseRefactor(DiagKindRefactor::sema_invalid_forced_cast_expr, afce); - } else { - (void)Synthesize(ctx, afce.rightExpr.get()); - } + // Juxtaposition `(U)e` with no ordinary reading and a non-type `U`: let the + // operand's own diagnostics surface. + (void)Synthesize(ctx, afce.rightExpr.get()); afce.SetTy(TypeManager::GetInvalidTy()); return TypeManager::GetInvalidTy(); } diff --git a/src/Sema/TypeCheckerImpl.h b/src/Sema/TypeCheckerImpl.h index 064750bd..bf89af9b 100644 --- a/src/Sema/TypeCheckerImpl.h +++ b/src/Sema/TypeCheckerImpl.h @@ -795,7 +795,7 @@ class TypeChecker::TypeCheckerImpl { OwnedPtr BuildForcedCastCall( AST::AmbiguousForcedCastExpr& afce, Ptr targetTy, Ptr operandTy); Ptr DesugarAmbiguousOrdinaryCall( - const CheckerContext& ctx, AST::AmbiguousForcedCastExpr& afce, bool typeValid); + const CheckerContext& ctx, AST::AmbiguousForcedCastExpr& afce); void PreCheckAmbiguousForcedCastType(ASTContext& ctx, AST::AmbiguousForcedCastExpr& afce, unsigned walkerID); Ptr SynAssignExpr(ASTContext& ctx, AST::AssignExpr& ae); Ptr SynMultipleAssignExpr(ASTContext& ctx, AST::AssignExpr& ae); diff --git a/unittests/Macro/NodeSerializationTest.cpp b/unittests/Macro/NodeSerializationTest.cpp index 88d02f42..fc1264b5 100644 --- a/unittests/Macro/NodeSerializationTest.cpp +++ b/unittests/Macro/NodeSerializationTest.cpp @@ -156,6 +156,36 @@ TEST_F(NodeSerializationTest, UnaryExpr_Serialization) free(rawBuffer); } +TEST_F(NodeSerializationTest, AmbiguousForcedCastExpr_Serialization) +{ + const std::string forcedCastExpr = "(Foo)handle"; + SourceManager sm; + sm.AddSource("./", forcedCastExpr); + DiagnosticEngine diag; + diag.SetSourceManager(&sm); + Parser parser{forcedCastExpr, diag, sm}; + auto ptr = parser.ParseExpr(); + ASSERT_EQ(ptr->astKind, ASTKind::AMBIGUOUS_FORCED_CAST_EXPR); + + NodeWriter writer(ptr.get()); + uint8_t* rawBuffer = writer.ExportNode(); + ASSERT_NE(rawBuffer, nullptr); + uint8_t* buffer = rawBuffer + 4; + auto fbNode = NodeFormat::GetNode(buffer); + ASSERT_EQ(fbNode->root_type(), NodeFormat::AnyNode_EXPR); + auto fbExpr = fbNode->root_as_EXPR(); + ASSERT_EQ(fbExpr->expr_type(), NodeFormat::AnyExpr_AMBIGUOUS_FORCED_CAST_EXPR); + auto fbForcedCast = fbExpr->expr_as_AMBIGUOUS_FORCED_CAST_EXPR(); + ASSERT_NE(fbForcedCast, nullptr); + EXPECT_EQ(fbForcedCast->type()->type_type(), NodeFormat::AnyType_REF_TYPE); + EXPECT_EQ(fbForcedCast->type()->type_as_REF_TYPE()->ref()->identifier()->str(), "Foo"); + EXPECT_EQ(fbForcedCast->expr()->expr_type(), NodeFormat::AnyExpr_REF_EXPR); + EXPECT_EQ(fbForcedCast->expr()->expr_as_REF_EXPR()->ref()->identifier()->str(), "handle"); + EXPECT_EQ(fbForcedCast->left_paren_pos()->column(), 1); + EXPECT_EQ(fbForcedCast->right_paren_pos()->column(), 5); + free(rawBuffer); +} + TEST_F(NodeSerializationTest, VarDecl_Serialization) { SourceManager sm;