Note:
when operating on a Type hierarchy with LeafType inheriting from MiddleType which inherits from mlir::Type.
calling LeafType::classof(MiddleType) will always return false.
because classof call the static getTypeID from its parent instead of the dynamic Type::getTypeID
so classof in this context will check if the TypeID of LeafType is the same as the TypeID of MiddleType which is always false.
It is bypassed in this commit inside CastInfo<To, From>::isPossible by calling classof with an mlir::Type.
but other unsuspecting users of LeafType::classof(MiddleType) would still get an incorrect result.
Details
- Reviewers
rriddle mehdi_amini bzcheeseman
Diff Detail
Event Timeline
+1 to the concept, many thanks for this! I think it makes more sense to implement the member versions with the llvm-style versions, it should simplify the member style code because then you won't have to manually implement the classof/isa/cast innards it'd just be cast<T>(*this) or something.
mlir/unittests/IR/TypeTest.cpp | ||
---|---|---|
29 | _or_null is deprecated, please use _if_present |
I think both casting system will stay available. so I am not sure it matters.
i found out that some Types can "inherit" from other type so it makes sense to cast from a more then just mlir::Type.
so I added support for that. it may be good to rereview
mlir/unittests/IR/TypeTest.cpp | ||
---|---|---|
29 | it isn't appear to be attributed as such. |
mlir/unittests/IR/TypeTest.cpp | ||
---|---|---|
29 | We didn't want to add a bunch of build spew for all LLVM users immediately, it will be marked deprecated at some point (hopefully) soon. |
I think both casting system will stay available. so I am not sure it matters.
Actually we should likely deprecated the old-style in the future, so the suggestion above gives a nicer path to get there.
I updated to to have the member version of cast/isa/dyn_cast depend on the out of line ones.
and I found an interesting bug. when having a type hierarchy like the following
struct LeafType; struct MiddleType : Type::TypeBase<MiddleType, Type, TypeStorage> { using Base::Base; static bool classof(Type ty) { return ty.getTypeID() == TypeID::get<LeafType>() || Base::classof(ty); } }; struct LeafType : Type::TypeBase<LeafType, MiddleType, TypeStorage> { using Base::Base; };
calling LeafType::classof(MiddleType) will always return false.
here is the current implementation of StorageUserBase::classof
template <typename T> static bool classof(T val) { static_assert(std::is_convertible<ConcreteT, T>::value, "casting from a non-convertible type"); return val.getTypeID() == getTypeID(); }
When T is not mlir::Type, val.getTypeID() will call the static getTypeID from its parent instead of the dynamic Type::getTypeID
so classof in the context will check if the TypeID of LeafType is the same as the TypeID of MiddleType which is always false.
It is "solved" in the current version of the patch inside CastInfo<To, From>::isPossible by calling classof with an mlir::Type.
but other unsuspecting users of LeafType::classof(MiddleType) would still get an incorrect result.
is there any benefit to having Type::getTypeID and StorageUserBase::getTypeID have the same name ?
should the StorageUserBase::getTypeID change name to avoid this issue?
or make classof Take a mlir::Type.
also is StorageUserBase used for attributes ?
mlir/include/mlir/IR/Types.h | ||
---|---|---|
328 | Not sure if you saw https://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html#advanced-use-cases but you might be able to use some cast traits since Type is nullable. I think you can use CastIsPossible, NullableValueCastFailed, and DefaultDoCastIfPossible. The default CastIsPossible also checks if the types are the same or related by inheritance and always allows casting from derived to base. For context, that example nullable type was more or less based on mlir::Type. |
mlir/include/mlir/IR/Types.h | ||
---|---|---|
328 | thanks for the tip, I added NullableValueCastFailed and DefaultDoCastIfPossible |
Thanks for fixing the or_null to if_present too (where it makes sense). LGTM as long as everything passes CI :)
mlir/include/mlir/IR/Types.h | ||
---|---|---|
341 | I take it this means you can't use the CastIsPossible<To, From> trait? |
mlir/include/mlir/IR/Types.h | ||
---|---|---|
341 | I couldn't get it to work easily. I think i could have by insisting a bit more but it was in my opinion more trouble then it was worth. CastIsPossible by default passes pointers to classof. so it doesn't work for us. we could always add an and not up-cast in our SFINAE but this is in my opinion more trouble that it is worth. |
Can you add a one-line comment here?