Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to check validity of default parameter values, of generic types? #1353

Open
jaehyun1ee opened this issue Dec 2, 2024 · 0 comments
Open

Comments

@jaehyun1ee
Copy link
Contributor

I wonder how the P4 frontend should check the validity of default parameter value, of generic type. The spec allows supplying default values for parameters, but does not explain much about their typing:

If a parameter has a default value and no corresponding argument is supplied, the default value is used as an argument. (section 6.8)

Take this code for example (a slight variant of the code example in section 6.8.2),

 struct intrinsic_metadata_t {
    bit<8> f0;
    bit<8> f1;
 }

 struct empty_t {}

 control nothing(inout empty_t hdr, inout empty_t meta, in intrinsic_metadata_t imeta) {
    apply {}
 }

 control C<H, M>(
     inout H hdr,
     inout M meta,
     in intrinsic_metadata_t intr_md);

 package P<H, M>(C<H, M> c = nothing());

 P<_, _>() main;

Here, nothing() is a default parameter value for the generic parameter c of type C<H, M>.

Question 1. How do we check the validity of the package declaration package P<H, M>(C<H, M> c = nothing());?

Checking the validity of default values without generics is, straightforward.

extern void h(in bit<32> a, in bool b = true);

Here, we check that the default value true for b is indeed bool type, so h is a valid extern function declaration.

But for the given example, should the frontend check if nothing() is unifiable to type C<H, M>?

Question 2. Does default parameter value impose a type constraint?

Let's introduce type some_t and a control declaration something that has type C<some_t, some_t>.

 struct some_t { bit<32> b; }

 control something(inout some_t hdr, inout some_t meta, in intrinsic_metadata_t imeta) {
    apply {}
 }

 P(something()) main;

Should we check the program as valid or not?

It depends on the decision whether the type constraint H = M = empty_t implied by the declaration package P<H, M>(C<H, M> c = nothing()); persists throughout the program, or is discarded.

If the constraint persists, then we should reject the instantiation P(something()) main;, since it implies H = M = some_t != empty_t.

If the constraint is discarded, then we can accept the instantiation P(something()) main;.

Question 3. What if there are multiple generic parameters with default values?

The problem gets even more complicated with multiple generic parameters with defaults.

 struct intrinsic_metadata_t {
    bit<8> f0;
    bit<8> f1;
 }

 struct empty_t {}
 struct some_t { bit<32> b; }

 control nothing(inout empty_t hdr, inout empty_t meta, in intrinsic_metadata_t imeta) {
    apply {}
 }

 control something(inout some_t hdr, inout some_t meta, in intrinsic_metadata_t imeta) {
    apply {}
 }

 control C<H, M>(
     inout H hdr,
     inout M meta,
     in intrinsic_metadata_t intr_md);

 package P<H, M>(C<H, M> c = nothing(), C<H, M> d = something());

Now, parameters c and d imply conflicting type variable resolutions.
c implies H = M = empty_t while d implies H = M = some_t, where empty_t and some_t are distinct types.

Then, do we consider the package declaration as valid?

If we treat default parameter values independently, then we may accept the declaration as valid. But this may introduce some confusion in the instantiation sites of the package. For example,

P() main; // is invalid since nothing() and something() impose conflicting type constraints
P(c = something()) main; // is valid
P(d = nothing()) main; // is valid

If we take them collectively, i.e., unifying C<H, M> c = nothing(), C<H, M> d = something() altogether, the declaration should result in a type error.

Personal Thoughts

So there are multiple design questions regarding this feature: lifetime of an implicit type constraint (persists throughout the program or discarded) and span of type constraint (independently or collectively).

IMHO, I would propose specifying (i) type constraint implied by default parameter value does not persist across the program and (ii) default parameter values are unified collectively.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant