Re: [sv-bc] Search order for functions/tasks in modules, $unit and packages

From: Gordon Vreugdenhil <gordonv_at_.....>
Date: Fri Aug 26 2005 - 13:19:30 PDT
Let me take a crack at the name resolution scenarios
that Mark raised and add a few more really bad cases.

Since forward references to subprograms (tasks/functions) are
historically legal, they must be treated a bit differently.

Here is a semi-operational description of what I think the
combination of the P1800 LRM rules and historical behavior requires:
     1) a task/function reference cannot be resolved upwards
        from a scope until the scope (and possibly parents) are
        complete.
     2) a tack/function reference does inspect imports in an
        eager manner but doesn't look upwards until (1) is
        satisfied.
     3) all other non-type resolution that escapes to $unit must
        also be deferred but is done in an "eager" manner in the
        intervening scopes.
     4) any identifier is located upwards, including $unit seen
        "so far" and its imports and resolution occurs immediately
        if the identifier can be resolved to a type.
     5) a "potentially visible name" becomes directly visible as
        early as possible but "upwards" potential visibility
        can be deferred by earlier rules.


Not the most obvious set of rules, but I think that this
is pretty close.

Here are the implications of this for each of the designs:


1)


function int fn();
   return 0;
endfunction

module m();
int x;
initial x = fn(); // which fn() does this bind to?

function int fn()
   return 1;
endfunction

endmodule


In "x = fn()", fn means m.fn by rule 1.



2)

package p;
function int fn();
   return 0;
endfunction
endpackage

module m();
import p::*;
int x;
initial x = fn(); // which fn() does this bind to?

function int fn()
   return 1;
endfunction
endmodule


By rule 2, fn() binds to p::fn, making it directly visible
in m.  This causes the declaration of m.fn to produce an error.


3)


package p;
function int fn();
   return 0;
endfunction
endpackage

import p::*;

module m();
int x;
initial x = fn(); // which fn() does this bind to?

function int fn()
   return 1;
endfunction
endmodule


By rule 2, fn() binds to m.fn since you don't inspect
the parent's import until the module scope is closed.

This also implies that "fn" is not imported into
$unit and thus declaring a new "fn" inside $unit
would be legal.


4)


package p;
function int fn();
   return 0;
endfunction
endpackage

import p::*;

module m();
int x;
initial x = fn(); // which fn() does this bind to?
endmodule

function int fn()
   return 1;
endfunction


This is an error.  By rule 1 & 2, upon completing the module
scope, "fn" is found via the import.  $unit::fn then conflicts
with the visible p::fn.


5)
      module m;
      parameter p = 1;
      function int fn();
         return 0;
      endfunction
      if (p) begin:b   // generate
          reg x = fn();
          function int fn();
              return 1;
          endfunction
      end
      endmodule


fn() binds to m.b.fn() since it is not resolved until the
close of the generate scope.


6)
      // file mode compilation unit
      module m;
         int x = fn();
      endmodule
      function int fn();
          return 1;
      endfunction


No error.  The foward reference is resolved in $unit
when $unit is closed.


7)
      // file mode compilation unit
      module m;
         int x = a;   // error?
      endmodule
      localparam a = 1;


No error.  "a" is not resolved until $unit is closed.


8)

      typedef int T;
      module m;
         T x;
         typedef real T;
         T y;
      endmodule


This one is nasty.  By rule 4,  the $unit version of T
is visible in "m" during the declaration of x.  But
since this isn't an import, there is no expectation that
"T" can't be redefined in m.  This implies that this
design is legal with x being an int and y being a real.

9)
     module foo;
       reg x;

       initial begin:b
         automatic reg y = x;
         automatic reg x;
       end
     endmodule


Similar case to (8) but follows rule (3).







I am not at all happy by my read of things in terms of
the rule set that I outlined above.


For types we *must* have early resolution due to parse
issues.  And for historical reasons, we really need to
preserve the subprogram resolution behavior.

So, why not require that all non-subprogram resolution
be done in the same manner as types *with* the additional
requirement that any non-imported escaping reference
becomes a "reserved" identifier in the referring scope
so that no local redefinition of the name is permitted.

Then subprograms are the only case where we have special
rules.


Such an approach would make the egregiously bad cases
(8 & 9) illegal and, if I had my way, would also make
7 illegal since "a" is a non-subprogram reference.



Anyways, feedback and discussion is clearly welcome on
this.


Gord.


-- 
--------------------------------------------------------------------
Gordon Vreugdenhil                                503-685-0808
Model Technology (Mentor Graphics)                gordonv@model.com
Received on Fri Aug 26 13:19:37 2005

This archive was generated by hypermail 2.1.8 : Fri Aug 26 2005 - 13:21:51 PDT