Tapioca::Dsl::Compilers::ActiveJob creates an invalid RBI for generic job classes
Given classes like this
class Operation
abstract!
sig { abstract.void }
def save!; end
end
class OperationJob < Active::Job
extend T::Sig
extend T::Generic
abstract!
OperationType = type_member { { upper: Operations::Model } }
sig { returns(OperationType) }
attr_reader :operation
sig { abstract.returns(T::Class[OperationType]) }
def operation_type; end
def perform(**args)
@operation = operation_type.new(**args)
@operation.save!
end
end
The compiler produces output like this
class. OperationJob
class << self
sig do
params(
args: T.untyped,
block: T.nilable(T.proc.params(job: OperationJob).void)
).returns(T.any(OperationJob, FalseClass))
end
def perform_later(**args, &block); end
sig { params(args: T.untyped).returns(T.untyped) }
def perform_now(**args); end
end
end
This fails type checking with the error Malformed type declaration. Generic class without type arguments.
Locally we worked around this by monkey patching the compiler to skip generics by calling
def decorate
return if constant.is_a?(T::Generic)
# continue with existing code
end
Should this change be upstreamed? If so I'm happy to submit a PR
You shouldn't need to skip generics, I think we can generate a generic type in the method signature instead, OperationJob[T.untyped]. Assuming T.untyped will be okay with any given upper/lower bound.
Also instead of the is_a? it'll be better to do T::Generic === constant to cover for the possibility of being overwritten.
This looks similar to https://github.com/Shopify/job-iteration/issues/550 A fix similar https://github.com/Shopify/job-iteration/pull/556 to should address the problem.