Description
This issue tracks multiple steps of inferring and constraining type variables, aka generics.
- Limited Support for user-defined generics
- Call site type variable inference
- 1. Bugfix: "Unrolled" type variables need to be "rerolled" or otherwise have their number of pointers tracked
- 2. Rewrite malloc, etc. as generic functions
- a. Store type variable data in constraint variables
- b. Rewrite
void*
asT*
with_Itype_for_any(T)
annotation on functions
- 3. Add constraints based on type variables
- 4. Extend to multiple type variables per function by analyzing call site consistency
- 5. Generalize type variable depth, ie T**
- 6. Consider unsafe and itype generics
- 7. Research
__BoundsInterface
that may be present on checkedc type variables and incorporate it.
Existing code allows users to write generic functions with multiple type variables, as long as function parameters are each a single pointer to the type. It will also add type arguments to call sites.
-
There is a bug that adds pointers to generic types when these are compared to other types. The comparison may not be necessary (stop it at a generic base type as success), but may be more important in further steps here. Include a count of a number of pointers in constraint variable so that later comparisons or rewriting can be consistent with the intended type. The pointers are added in
ConstraintVariables.cpp::getAtom()
-
Split into two parts for convenience.
a) Next step is to rewrite functions defined with
void*
parameters. This will require creation of type variables, so theefunction and constraint variables need to store them. Luckily, code only relies on per-call site type variable indexes, so a function can store the number of type variables, and a variable can store an index. Existing code that looks up these indexes, especiallyUtils.cpp::getTypeVariableType()
needs to be moved into the constraint variable creation stage.b) To allow rewriting, we need to check for
void*
parameters and returns in functionCVs. These can be converted intoT*
. This can be done by changing theGenericIndex
and adding code to stop rewriting atT
, similar to the typedef code. Or by creating and inserting aTypeDefType
with aTypeVariableType
inside to use the typedef code as is happening currently. The rewriter can then check for changes and insert the new types. Parameters should work with little to no changes, butItype_for_any(T)
has never yet been inserted into code. -
We need generic index constrain propagation for the more useful aspects of generic inference. Since 3C is not set up for this, it means new
atom
s or new constraint resolution code. Research the possibilities and implement a way to rewritevoid*
decls as_Ptr<T>
within a function that uses the variable appropriately. -
Next we infer the number of type variables of a generic function by creating and analyzing call site constraints. Current code checks consistency of arguments against their type variable index, but here we take it further and assume each inconsistency is a new type variable (for generated code).
TypeVariableAnaysis.cpp::updateEntry()
and its callers will need to be rewritten and be able to update function and variable constraints. -
So far all code assumes that generic constraint variables are of the form
T*
. We need to generalize to any number of pointers to support all code. This will complicate most of the code written for the above steps. In particular, loops will be needed to find pointer depth. Code used to work with typedef level could be copied or reused for this purpose. There is also a bug where the solved generic variable in one callsite interferes with another. Handling this step properly should solve the bug, which may be a good place to start. See type_params_xfail1.c -
Generics are only rewritten if all params are safe. This means we'll always have
_Ptr<T> i
and neverT* i : Itype(_Ptr<T>)
. It's uncertain if this capability will be of much use. -
Internally to CheckedC, type variables have a
__BoundsInterface
. This is likely an advanced interface for checking bounds of arrays deeper within the type variable. Research what it really is, why it may be important, and implement it.
Additionally, constraint variables used as a function's internal parameters may not need to be marked as generic. After a pending pull request they will be independent of the external parameters and may only need to be created with a base type T
to be used properly. Reevaluate after the code is included.