diff --git a/source/ast/expressions/ConversionExpression.cpp b/source/ast/expressions/ConversionExpression.cpp index 1062582aa..7cfd5db73 100644 --- a/source/ast/expressions/ConversionExpression.cpp +++ b/source/ast/expressions/ConversionExpression.cpp @@ -413,9 +413,9 @@ Expression& ConversionExpression::fromSyntax(Compilation& comp, const CastExpres // The type we propagate should use the sign of the operand, just like it // would if we were doing an implicit conversion via an assignment expression. auto propagatedType = type; - if (type->isIntegral() && operand->type->isIntegral() && - type->getIntegralFlags() != operand->type->getIntegralFlags()) { - propagatedType = &comp.getType(type->getBitWidth(), operand->type->getIntegralFlags()); + if (type->isNumeric() && operand->type->isNumeric()) { + propagatedType = OpInfo::binaryType(comp, type, operand->type, false, + /* signednessFromRt */ true); } contextDetermined(context, operand, nullptr, *propagatedType, syntax.apostrophe.range(), diff --git a/tests/unittests/ast/ExpressionTests.cpp b/tests/unittests/ast/ExpressionTests.cpp index 642305bfd..ab9d2d94a 100644 --- a/tests/unittests/ast/ExpressionTests.cpp +++ b/tests/unittests/ast/ExpressionTests.cpp @@ -3788,3 +3788,20 @@ endmodule compilation.addSyntaxTree(tree); NO_COMPILATION_ERRORS; } + +TEST_CASE("Static casts propagate type correctly and don't truncate") { + auto tree = SyntaxTree::fromText(R"( +typedef logic [6:0] lt; +function automatic logic[7:0] foo; + logic [7:0] a = 8'hff; + lt b = lt'(a >> 1); + return 8'(b); +endfunction + +$static_assert(foo() == 8'h7f); +)"); + + Compilation compilation; + compilation.addSyntaxTree(tree); + NO_COMPILATION_ERRORS; +}