Skip to content

Commit c256630

Browse files
committed
static_cast bugfixes when:
- upcasting from generic object to native types ( completely disallowed to upcast object ) - access field on upcast struct from generic csp.Struct type ( Was crashing ) Signed-off-by: Rob Ambalu <robert.ambalu@point72.com>
1 parent c1c9f3e commit c256630

3 files changed

Lines changed: 21 additions & 2 deletions

File tree

cpp/csp/cppnodes/baselibimpl.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,9 @@ DECLARE_CPPNODE( struct_field )
628628
START()
629629
{
630630
auto * structType = static_cast<const CspStructType *>( x.type() );
631+
//Special check for null meta ( csp.Struct type ) which can end up here from a csp.static_cast
632+
if( !structType -> meta() )
633+
CSP_THROW( TypeError, "Struct csp.Struct has no field named " << field.value() );
631634
m_fieldAccess = structType -> meta() -> field( field );
632635
if( !m_fieldAccess )
633636
CSP_THROW( TypeError, "Struct " << structType -> meta() -> name() << " has no field named " << field.value() );

csp/baselib.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -763,8 +763,11 @@ def static_cast(x: ts["T"], outType: "U") -> ts["U"]:
763763
This should only be used when the caller knows with 100% certainty that the type conversion is always valid
764764
as there will be no runtime type checking.
765765
"""
766-
# Special case bool / int which are native types, but bool evaluates as a subclass of int
767-
if not issubclass(outType, x.tstype.typ) or (outType is bool and x.tstype.typ is int):
766+
# Allow static_cast on subclass types except for these exceptions:
767+
# - type object which is a base of everything
768+
# - case bool / int which are native types, but bool evaluates as a subclass of int
769+
770+
if x.tstype.typ is object or not issubclass(outType, x.tstype.typ) or (outType is bool and x.tstype.typ is int):
768771
raise TypeError(f"Unable to csp.static_cast edge of type {x.tstype.typ.__name__} to {outType.__name__}")
769772
return Edge(ts[outType], nodedef=x.nodedef, output_idx=x.output_idx, basket_idx=x.basket_idx)
770773

csp/tests/test_baselib.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,6 +1207,7 @@ class D(Base):
12071207
x_int = csp.const(1)
12081208
x_bool = csp.const(True)
12091209
x_float = csp.const(123.456)
1210+
x_object = csp.const.using(T=object)(1)
12101211

12111212
x_b = csp.const.using(T=Base)(D(a=1, b=2.1))
12121213

@@ -1228,10 +1229,22 @@ def g():
12281229
with self.assertRaisesRegex(TypeError, "Unable to csp.static_cast edge of type int to bool"):
12291230
csp.run(csp.static_cast(x_int, bool), starttime=utc_now(), endtime=timedelta())
12301231

1232+
with self.assertRaisesRegex(TypeError, "Unable to csp.static_cast edge of type object to int"):
1233+
csp.run(csp.static_cast(x_object, int), starttime=utc_now(), endtime=timedelta())
1234+
12311235
# Runtime type check
12321236
with self.assertRaisesRegex(TypeError, 'expected output type on .* to be of type "int" got type "float"'):
12331237
csp.run(csp.dynamic_cast(x_float, int), starttime=utc_now(), endtime=timedelta())
12341238

1239+
class S(csp.Struct):
1240+
a: int
1241+
1242+
with self.assertRaisesRegex(TypeError, "Struct csp.Struct has no field named a"):
1243+
# Was a crash before, dont crash on struct_field access when upcast from csp.Struct which has no metadata
1244+
csp.run(
1245+
csp.static_cast(csp.const.using(T=csp.Struct)(S(a=1)), S).a, starttime=utc_now(), endtime=timedelta()
1246+
)
1247+
12351248

12361249
if __name__ == "__main__":
12371250
unittest.main()

0 commit comments

Comments
 (0)