Inheritance of properties
Check out the LRM on functions and pass by reference

IEEE Std 1800-2012 &sect; 13.4 Functions:


  It shall be illegal to call a function with output, inout, or ref arguments in an event expression, in an expression within a procedural continuous assignment, or in an expression that is not within a procedural statement. However, a const ref function argument shall be legal in this context (see 13.5.2).


IEEE Std 1800-2012 &sect; 13.5.2 Pass by reference:


  Arguments passed by reference are not copied into the subroutine area, rather, a reference to the original argument is passed to the subroutine. The subroutine can then access the argument data via the reference. Arguments passed by reference shall be matched with equivalent data types (see 6.22.2). No casting shall be permitted. To indicate argument passing by reference, the argument declaration is preceded by the ref keyword. It shall be illegal to use argument passing by reference for subroutines with a lifetime of static. The general syntax is as follows:
  subroutine( ref type argument );


You can try:

function automatic states next_state_func (
  const ref states curr_state,
  const ref logic reset,
  const ref {type} some_signal_a,
  const ref {type} some_signal_b);
...
endfunction

I'm not sure if it can synthesize. I haven't seen any documentation that give guidance on functions with ref synthesize. I always use ref for test-bench related area. When coding RTL, I calculate the next_state inside an always_comb without any function calls.



Other issue:
Do not put assign inside procedural blocks. Refer to IEEE Std 1800-2012 &sect; C.4.2 Procedural assign and deassign statements


  The procedural assign and deassign statements can be a source of design errors and can be an impediment to tool implementation. The procedural assign and deassign statements do not provide a capability that cannot be done by another method that avoids these problems. Therefore, the procedural assign and deassign statements are on a deprecation list. ...
  
  ...
  
  Allowing the assign statement to be used both inside and outside a procedural block causes confusion and is a source of errors in SystemVerilog models. The practice of using the assign and deassign statements inside procedural blocks is highly discouraged.


Your code should be:

always_comb begin
  next_state = ...
end


or 

assign next_state = ...