typedb/typeql

Sanitize rust macros to avoid forcing user's environment

Closed this issue · 0 comments

Problem to Solve

Currently the builder macros rely on a particular lexical environment.
For example

typeql_lang::typeql_define()
// will expand to
TypeQLDefine::new(vec![])

requiring the user to have TypeQLDefine in the lexical environment.

This is a problem because it lets users do this sort of thing:

struct TypeQLDefine;
impl TypeQLDefine {
  fn new(Vec<typeql_lang::pattern::Definable>) -> Self { Self }
}

// somewhere where that TypeQLDefine is in scope...
typeql_define!(my_type, my_rule) // <-- this line doesn't error

This is a minimal example, but you can see where major problems can arise.

Proposed Solution

Using proper rust macro hygiene fixes this issue, by expanding to fully qualified identifiers.

To fix the define query, for example, is as simple as replacing it with

#[macro_export]
macro_rules! typeql_define {
    ($($pattern:expr),* $(,)?) => {{
        $crate::query::TypeQLDefine::new(vec![$($pattern.into()),*])
    }}
}

With this we have

typeql_define!()
// will expand to
typeql_lang::query::TypeQLDefine::new(vec![])

Read more on macro hygiene at: https://veykril.github.io/tlborm/decl-macros/minutiae/hygiene.html