message: Prehash keys of dictionaries
  Summary: If all the keys are constant we can hash them at compile time.
diff: @@ -418,10 +418,8 @@ impl Compiler<'_> {
  }
  Expr::Dict(exprs) => {
  let xs = exprs.into_map(|(k, v)| (self.expr(k), self.expr(v)));
  - if xs
  - .iter()
  - .all(|(k, v)| k.as_value().is_some() && v.as_value().is_some())
  - {
  + if xs.iter().all(|(k, _)| k.as_value().is_some()) {
  + if xs.iter().all(|(_, v)| v.as_value().is_some()) {
  let mut res = SmallMap::new();
  for (k, v) in xs.iter() {
  res.insert_hashed(
  @@ -439,6 +437,33 @@ impl Compiler<'_> {
  let result = self.heap.alloc(FrozenDict::new(res));
  return expr!(|eval| eval.heap().alloc_thaw_on_write(result));
  }
  + } else {
  + // The keys are all constant, but the variables change.
  + // At least we can pre-hash these values.
  + let xs = xs.into_map(|(k, v)| {
  + (
  + k.as_value()
  + .unwrap()
  + .get_hashed()
  + .expect("Dictionary literals are hashable"),
  + v.as_compiled(),
  + )
  + });
  + return expr!(|eval| {
  + let mut r = SmallMap::with_capacity(xs.len());
  + for (k, v) in &xs {
  + if r.insert_hashed(k.to_hashed_value(), v(eval)?).is_some() {
  + throw(
  + Err(EvalError::DuplicateDictionaryKey(k.key().to_string())
  + .into()),
  + span,
  + eval,
  + )?;
  + }
  + }
  + eval.heap().alloc(Dict::new(r))
  + });
  + }
  }
  let xs = xs.into_map(|(k, v)| (k.as_compiled(), v.as_compiled()));
  