$cast() vs. UVM type override

Hi,

What is the relationship between SV dynamic cast $cast() and UVM type override? Does SV $cast() know anything about type overrides made by UVM? Based on the following example, it does… Does it come from that statement in the LRM 1800-2012, 8.16 Casting:

… and the source is an object that is assignment compatible with the destination type. This type of assignment requires a run-time check as provided by $cast.

What does that mean?

module test_module ();
`include "macros.svh"
`include "uvm_macros.svh"
  import uvm_pkg::*;

  class agent_a extends uvm_agent;
    `uvm_component_utils(agent_a)
  
    function new(string name = "agent_a", uvm_component parent = null);
      super.new(name, parent);
    endfunction : new
  endclass : agent_a
  
  class agent_b extends agent_a;
    `uvm_component_utils(agent_b)
    
    string field = "field";
  
    function new(string name = "agent_b", uvm_component parent = null);
      super.new(name, parent);
    endfunction : new
  endclass : agent_b

  agent_a agent_a_h;
  uvm_agent temp;
  agent_b agent_b_h;
  agent_a agent_a_h_2;
  int cast1, cast2, cast3;

  initial begin
    agent_a::type_id::set_type_override(agent_b::get_type());
    factory.print();
    agent_a_h = agent_a::type_id::create("agentti_h", null);
    temp = agent_a_h;
    cast1 = $cast(agent_a_h_2, agent_a_h); // This $cast works also with type override, why?
    cast2 = $cast(agent_b_h, agent_a_h);  // This $cast won't work without type override, why?
    cast3 = $cast(agent_b_h, temp);  // This $cast won't work without type override either.
    $display("casts = ", cast1, cast2, cast3);
    $display("field = ", agent_b_h.field);
  end
endmodule : test_module

Thank you already in advance!

-ilia

In reply to ilia:
ilia,

The UVM is just SystemVerilog code organized into a package. The UVM factory creates objects by doing indirect calls to an objects constructor, new(), via a create() method. The create() method usually constructs the requested class type, but first checks to see if someone has applied an a type override setting, and constructs an object of that type instead. The overridden type is always a derived type of the requested type. So the create() method always returns an object who class type is the same as the requested type, or an extension of that class type. Once you have a handle to object, the standard SystemVerilog rules for inheritance and assignment to class variables apply.

I explain this in detail in my new SystemVerilog OOP for UVM Verification course.

In reply to dave_59:

Yep, you are right. So, in my example, with the type override applied, cast1 = $cast(agent_a_h_2, agent_a_h); works also because, the class type of agent_a_h is actually agent_b which in turn is subclass of agent_a, right? It is always legal to assign a subclass object handle to a variable of the superclass which results in a successful cast in that case?

-ilia

In reply to ilia:
Correct. In the cases where the type of the class variable being assigned cannot fail, you can do a direct assignment without using $cast.

In reply to dave_59:

Nice, I am cleverer now, thanks!

In reply to ilia:

I think the three $cast all return 1.