Hierarchical referencing within hierarchy of class objects

Have a small design where an environment class has two different objects driver1 and drive2 instantiated in it.
I am trying to access a class variable in driver1 from driver2 using Hierarchical referencing in the task printRefPartial.
Here is a testbench:

`include "design.sv"
module tb ();
  
  env env_inst;
  
  initial begin :myblock
      $display("Starting");
      env_inst = new();
      #1;
      //
      $display("Class driver1, someint = %0d",env_inst.driver1_inst.someint);
      $display("Class driver2, someint = %0d",env_inst.driver2_inst.someint);
      //
      env_inst.driver2_inst.printRefPartial;
      env_inst.driver2_inst.printRefFull;
      //
      $display("Finishing");
      $finish;
    end :myblock
  
endmodule

Here are the classes in design.sv

// driver1 class
class driver1;
  int someint;

  function new();
    $display("Constructing driver1");
    someint = 1;
  endfunction
  
endclass
  
// driver2 class
class driver2;
  int someint;

  function new();
    $display("Constructing driver2");
    someint = 2;
  endfunction
  
  // Tools don't like this name
  task printRefPartial();
    $display("Ref partial path value = %0d",driver1_inst.someint);
  endtask  
  
  // Tools don't like this name
  task printRefFull();
    //$display("Ref full path value = %0d",myblock.env_inst.driver1_inst.someint);
  endtask
    
endclass

// env class has instance of driver1 & driver2
class env;
  driver1 driver1_inst;
  driver2 driver2_inst;
  
  function new ();
    driver1_inst = new;
    driver2_inst = new;
    $display("-----Constructing env-----");
  endfunction
  
endclass

Running the testbench produces:

** Error (suppressible): design.sv(23): (vopt-7063) Failed to find ‘driver1_inst’ in hierarchical name ‘$root.driver1_inst.someint’.

Region: testbench_sv_unit

It does not like my path?
Seems like it should work.
The simulator should not find driver1_inst.someint, but then should look up one level and the path should be found to its neighbor.

What am I missing?

In reply to mike_mentor:

Classes are dynamic objects, so hierarchical references are not allowed outside of local objects or imported packages.

In reply to cgales:

Are you saying that hierarchical referencing does not work from one class object instance to another?

I know that I can access ($display) the same class object instance in my example from the testbench.

Like in this line of the testbench

      $display("Class driver1, someint = %0d",env_inst.driver1_inst.someint);

In reply to mikefitzgerald:

That is because env_inst is a local object created by the testbench. Hence you can reference it hierarchically.

In your example, driver2 doesn’t create driver1, so it isn’t a local object. Therefore, you can’t reference it hierarchically.

In reply to cgales:

What is a ‘local object’?
The phrase is not found in the spec; and does not show up in internet searches.

In reply to mike_mentor:

I think local scope is the term you all are looking for.

A module and all procedural constructs like tasks/functions/begin/end blocks all create local scope, some of which can be nested. An instance of module tb creates a local scope of which env_inst is a member. Since there is only one instance of tb, you can refer to tb.env_int or explicitly $root.tb.env_inst from anywhere (except inside a package which does not allow any hierarchical references)

task printRefFull();
  $display("Ref full path value = %0d",$root.tb.env_inst.driver1_inst.someint);
endtask

If you have a statement inside a nested local scope (myblock), it can refer upwards to members in the outer scope directly. that is why the $display statements inside myblock work correctly.

The $display statement inside the task printRefPartial does not compile because there is no driver1_inst in the local scope of the task, nor is the a driver_inst inside the local scope of the class driver2. The local scope above the class is the compilation unit, and there is no driver1_inst there either. The fact that driver2 was constructed inside env does not make env an upwards scope to driver2. Objects get constructed dynamically during execution, and the search for identifiers needs to happen during compilation.

In reply to dave_59:

Based on this statement:
“Objects get constructed dynamically during execution, and the search for identifiers needs to happen during compilation”

Which makes sense, the dynamic object does not exist at compile time, how could it possibly be accessed???

Therefore, it seems like this task you tweaked for me should not work, because it refers to an object which is dynamic and does not exist at compile time. But it compiles, runs, and accesses the buried dynamic object (Questa/EDA Playground). There seems to be some way that the path to a future created object is allowed/reconciled/facilitated at compile time?
How does this work?

task printRefFull();
  $display("Ref full path value = %0d",$root.tb.env_inst.driver1_inst.someint);
endtask

In reply to mikefitzgerald:

This works because this is a combination of a hierarchical reference and a class member select.

$root.tb.env_inst is a hierarchical reference to a static class variable which is found via the rules I described.

env_inst.driver1_inst.someint is a class member select.

See section 23.7 Member selects and hierarchical names for a detailed explanation.