While implementing the compiler the design of the language has changed, from having a single 'root' implicit predicate only, to having a 'root' predicate along with optional 'child' predicates, to now having no 'root' predicate and only explicit named predicates.
The data structures used to represent a collection of predicates is now unfit for use. In particular, much of what was in the implicit predicate is copied into the child predicates as they're created, which is data that can go stale and also breaks values which are in a global namespace, especially const declarations.
The solution is to move most of what is in a Predicate back into the Contract. The predicate declarations have namespaces though and some data need to remain in the explicit predicate structs.
But which items should be allowed to be declared within predicate { ... } blocks? Currently the parser accepts anything except macros, storage, interfaces and consts.
This is probably OK. We could perhaps also disallow enum and new-type declarations (or they should at least be stored in the Contract and namespaced to the Predicate). Vars, state, constraints, if/else, non-expression macro calls and instances are the other items currently allowed.
All expressions must be stored in the Contract and only referred to from the Predicates though.
Tasks
[x] Move exprs from Predicate to Contract.
[x] Use a slotmap for preds and use a PredKey to refer to predicates instead of a reference or by name.
[x] Streamline Predicate:
[x] Move storage from Predicate to Contract.
[x] Move enums from Predicate to Contract.
[x] Move new_types from Predicate to Contract.
[x] Move interfaces from Predicate to Contract.
[x] Remove the concept of a 'root' predicate.
[x] Re-enable const arrays.
[x] Fix constant resolution in type aliases to arrays. (See E2E test root_types.)
[x] Refactor WithPred to either be WithCtx which includes the Contract or make it WithContract which takes a PredKey argument.
While implementing the compiler the design of the language has changed, from having a single 'root' implicit predicate only, to having a 'root' predicate along with optional 'child' predicates, to now having no 'root' predicate and only explicit named predicates.
The data structures used to represent a collection of predicates is now unfit for use. In particular, much of what was in the implicit predicate is copied into the child predicates as they're created, which is data that can go stale and also breaks values which are in a global namespace, especially
const
declarations.The solution is to move most of what is in a
Predicate
back into theContract
. The predicate declarations have namespaces though and some data need to remain in the explicit predicate structs.But which items should be allowed to be declared within
predicate { ... }
blocks? Currently the parser accepts anything except macros, storage, interfaces and consts.This is probably OK. We could perhaps also disallow enum and new-type declarations (or they should at least be stored in the
Contract
and namespaced to thePredicate
). Vars, state, constraints, if/else, non-expression macro calls and instances are the other items currently allowed.All expressions must be stored in the
Contract
and only referred to from thePredicate
s though.Tasks
exprs
fromPredicate
toContract
.slotmap
forpreds
and use aPredKey
to refer to predicates instead of a reference or by name.Predicate
:Predicate
toContract
.enums
fromPredicate
toContract
.new_types
fromPredicate
toContract
.interfaces
fromPredicate
toContract
.const
arrays.root_types
.)WithPred
to either beWithCtx
which includes theContract
or make itWithContract
which takes aPredKey
argument.