egglog 10.0.2__cp310-cp310-win_amd64.whl → 11.0.0__cp310-cp310-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of egglog might be problematic. Click here for more details.

egglog/builtins.py CHANGED
@@ -6,18 +6,20 @@ Builtin sorts and function to egg.
6
6
  from __future__ import annotations
7
7
 
8
8
  from collections.abc import Callable
9
+ from dataclasses import dataclass
9
10
  from fractions import Fraction
10
11
  from functools import partial, reduce
12
+ from inspect import signature
11
13
  from types import FunctionType, MethodType
12
14
  from typing import TYPE_CHECKING, Generic, Protocol, TypeAlias, TypeVar, cast, overload
13
15
 
14
- from typing_extensions import TypeVarTuple, Unpack
16
+ from typing_extensions import TypeVarTuple, Unpack, deprecated
15
17
 
16
- from .conversion import convert, converter, get_type_args
18
+ from .conversion import convert, converter, get_type_args, resolve_literal
17
19
  from .declarations import *
18
- from .egraph import BaseExpr, BuiltinExpr, expr_fact, function, get_current_ruleset, method
19
- from .functionalize import functionalize
20
- from .runtime import RuntimeClass, RuntimeExpr, RuntimeFunction
20
+ from .deconstruct import get_callable_args, get_literal_value
21
+ from .egraph import BaseExpr, BuiltinExpr, _add_default_rewrite_inner, expr_fact, function, get_current_ruleset, method
22
+ from .runtime import RuntimeExpr, RuntimeFunction, resolve_type_annotation_mutate
21
23
  from .thunk import Thunk
22
24
 
23
25
  if TYPE_CHECKING:
@@ -31,7 +33,7 @@ __all__ = [
31
33
  "BigRatLike",
32
34
  "Bool",
33
35
  "BoolLike",
34
- "BuiltinEvalError",
36
+ "ExprValueError",
35
37
  "Map",
36
38
  "MapLike",
37
39
  "MultiSet",
@@ -56,15 +58,17 @@ __all__ = [
56
58
  ]
57
59
 
58
60
 
59
- class BuiltinEvalError(Exception):
61
+ @dataclass
62
+ class ExprValueError(AttributeError):
60
63
  """
61
- Raised when an builtin cannot be evaluated into a Python primitive because it is complex.
62
-
63
- Try extracting this expression first.
64
+ Raised when an expression cannot be converted to a Python value because the value is not a constructor.
64
65
  """
65
66
 
67
+ expr: BaseExpr
68
+ allowed: str
69
+
66
70
  def __str__(self) -> str:
67
- return f"Cannot evaluate builtin expression into a Python primitive. Try extracting this expression first: {super().__str__()}"
71
+ return f"Cannot get Python value of {self.expr}, must be of form {self.allowed}. Try calling `extract` on it to get the underlying value."
68
72
 
69
73
 
70
74
  class Unit(BuiltinExpr, egg_sort="Unit"):
@@ -80,13 +84,21 @@ class Unit(BuiltinExpr, egg_sort="Unit"):
80
84
 
81
85
 
82
86
  class String(BuiltinExpr):
87
+ def __init__(self, value: str) -> None: ...
88
+
83
89
  @method(preserve=True)
90
+ @deprecated("use .value")
84
91
  def eval(self) -> str:
85
- value = _extract_lit(self)
86
- assert isinstance(value, str)
87
- return value
92
+ return self.value
88
93
 
89
- def __init__(self, value: str) -> None: ...
94
+ @method(preserve=True) # type: ignore[misc]
95
+ @property
96
+ def value(self) -> str:
97
+ if (value := get_literal_value(self)) is not None:
98
+ return value
99
+ raise ExprValueError(self, "String")
100
+
101
+ __match_args__ = ("value",)
90
102
 
91
103
  @method(egg_fn="replace")
92
104
  def replace(self, old: StringLike, new: StringLike) -> String: ...
@@ -103,17 +115,25 @@ converter(str, String, String)
103
115
 
104
116
 
105
117
  class Bool(BuiltinExpr, egg_sort="bool"):
118
+ def __init__(self, value: bool) -> None: ...
119
+
106
120
  @method(preserve=True)
121
+ @deprecated("use .value")
107
122
  def eval(self) -> bool:
108
- value = _extract_lit(self)
109
- assert isinstance(value, bool)
110
- return value
123
+ return self.value
124
+
125
+ @method(preserve=True) # type: ignore[misc]
126
+ @property
127
+ def value(self) -> bool:
128
+ if (value := get_literal_value(self)) is not None:
129
+ return value
130
+ raise ExprValueError(self, "Bool")
131
+
132
+ __match_args__ = ("value",)
111
133
 
112
134
  @method(preserve=True)
113
135
  def __bool__(self) -> bool:
114
- return self.eval()
115
-
116
- def __init__(self, value: bool) -> None: ...
136
+ return self.value
117
137
 
118
138
  @method(egg_fn="not")
119
139
  def __invert__(self) -> Bool: ...
@@ -138,21 +158,29 @@ converter(bool, Bool, Bool)
138
158
 
139
159
 
140
160
  class i64(BuiltinExpr): # noqa: N801
161
+ def __init__(self, value: int) -> None: ...
162
+
141
163
  @method(preserve=True)
164
+ @deprecated("use .value")
142
165
  def eval(self) -> int:
143
- value = _extract_lit(self)
144
- assert isinstance(value, int)
145
- return value
166
+ return self.value
167
+
168
+ @method(preserve=True) # type: ignore[misc]
169
+ @property
170
+ def value(self) -> int:
171
+ if (value := get_literal_value(self)) is not None:
172
+ return value
173
+ raise ExprValueError(self, "i64")
174
+
175
+ __match_args__ = ("value",)
146
176
 
147
177
  @method(preserve=True)
148
178
  def __index__(self) -> int:
149
- return self.eval()
179
+ return self.value
150
180
 
151
181
  @method(preserve=True)
152
182
  def __int__(self) -> int:
153
- return self.eval()
154
-
155
- def __init__(self, value: int) -> None: ...
183
+ return self.value
156
184
 
157
185
  @method(egg_fn="+")
158
186
  def __add__(self, other: i64Like) -> i64: ...
@@ -257,21 +285,29 @@ def count_matches(s: StringLike, pattern: StringLike) -> i64: ...
257
285
 
258
286
 
259
287
  class f64(BuiltinExpr): # noqa: N801
288
+ def __init__(self, value: float) -> None: ...
289
+
260
290
  @method(preserve=True)
291
+ @deprecated("use .value")
261
292
  def eval(self) -> float:
262
- value = _extract_lit(self)
263
- assert isinstance(value, float)
264
- return value
293
+ return self.value
294
+
295
+ @method(preserve=True) # type: ignore[misc]
296
+ @property
297
+ def value(self) -> float:
298
+ if (value := get_literal_value(self)) is not None:
299
+ return value
300
+ raise ExprValueError(self, "f64")
301
+
302
+ __match_args__ = ("value",)
265
303
 
266
304
  @method(preserve=True)
267
305
  def __float__(self) -> float:
268
- return self.eval()
306
+ return self.value
269
307
 
270
308
  @method(preserve=True)
271
309
  def __int__(self) -> int:
272
- return int(self.eval())
273
-
274
- def __init__(self, value: float) -> None: ...
310
+ return int(self.value)
275
311
 
276
312
  @method(egg_fn="neg")
277
313
  def __neg__(self) -> f64: ...
@@ -347,34 +383,34 @@ V = TypeVar("V", bound=BaseExpr)
347
383
 
348
384
  class Map(BuiltinExpr, Generic[T, V]):
349
385
  @method(preserve=True)
386
+ @deprecated("use .value")
350
387
  def eval(self) -> dict[T, V]:
351
- call = _extract_call(self)
352
- expr = cast("RuntimeExpr", self)
388
+ return self.value
389
+
390
+ @method(preserve=True) # type: ignore[misc]
391
+ @property
392
+ def value(self) -> dict[T, V]:
353
393
  d = {}
354
- while call.callable != ClassMethodRef("Map", "empty"):
355
- msg = "Map can only be evaluated if it is empty or a series of inserts."
356
- if call.callable != MethodRef("Map", "insert"):
357
- raise BuiltinEvalError(msg)
358
- call_typed, k_typed, v_typed = call.args
359
- if not isinstance(call_typed.expr, CallDecl):
360
- raise BuiltinEvalError(msg)
361
- k = cast("T", expr.__with_expr__(k_typed))
362
- v = cast("V", expr.__with_expr__(v_typed))
394
+ while args := get_callable_args(self, Map[T, V].insert):
395
+ self, k, v = args # noqa: PLW0642
363
396
  d[k] = v
364
- call = call_typed.expr
397
+ if get_callable_args(self, Map.empty) is None:
398
+ raise ExprValueError(self, "Map.empty or Map.insert")
365
399
  return d
366
400
 
401
+ __match_args__ = ("value",)
402
+
367
403
  @method(preserve=True)
368
404
  def __iter__(self) -> Iterator[T]:
369
- return iter(self.eval())
405
+ return iter(self.value)
370
406
 
371
407
  @method(preserve=True)
372
408
  def __len__(self) -> int:
373
- return len(self.eval())
409
+ return len(self.value)
374
410
 
375
411
  @method(preserve=True)
376
412
  def __contains__(self, key: T) -> bool:
377
- return key in self.eval()
413
+ return key in self.value
378
414
 
379
415
  @method(egg_fn="map-empty")
380
416
  @classmethod
@@ -417,24 +453,30 @@ MapLike: TypeAlias = Map[T, V] | dict[TO, VO]
417
453
 
418
454
  class Set(BuiltinExpr, Generic[T]):
419
455
  @method(preserve=True)
456
+ @deprecated("use .value")
420
457
  def eval(self) -> set[T]:
421
- call = _extract_call(self)
422
- if call.callable != InitRef("Set"):
423
- msg = "Set can only be initialized with the Set constructor."
424
- raise BuiltinEvalError(msg)
425
- return {cast("T", cast("RuntimeExpr", self).__with_expr__(x)) for x in call.args}
458
+ return self.value
459
+
460
+ @method(preserve=True) # type: ignore[misc]
461
+ @property
462
+ def value(self) -> set[T]:
463
+ if (args := get_callable_args(self, Set[T])) is not None:
464
+ return set(args)
465
+ raise ExprValueError(self, "Set(*xs)")
466
+
467
+ __match_args__ = ("value",)
426
468
 
427
469
  @method(preserve=True)
428
470
  def __iter__(self) -> Iterator[T]:
429
- return iter(self.eval())
471
+ return iter(self.value)
430
472
 
431
473
  @method(preserve=True)
432
474
  def __len__(self) -> int:
433
- return len(self.eval())
475
+ return len(self.value)
434
476
 
435
477
  @method(preserve=True)
436
478
  def __contains__(self, key: T) -> bool:
437
- return key in self.eval()
479
+ return key in self.value
438
480
 
439
481
  @method(egg_fn="set-of")
440
482
  def __init__(self, *args: T) -> None: ...
@@ -481,24 +523,30 @@ SetLike: TypeAlias = Set[T] | set[TO]
481
523
 
482
524
  class MultiSet(BuiltinExpr, Generic[T]):
483
525
  @method(preserve=True)
526
+ @deprecated("use .value")
484
527
  def eval(self) -> list[T]:
485
- call = _extract_call(self)
486
- if call.callable != InitRef("MultiSet"):
487
- msg = "MultiSet can only be initialized with the MultiSet constructor."
488
- raise BuiltinEvalError(msg)
489
- return [cast("T", cast("RuntimeExpr", self).__with_expr__(x)) for x in call.args]
528
+ return self.value
529
+
530
+ @method(preserve=True) # type: ignore[misc]
531
+ @property
532
+ def value(self) -> list[T]:
533
+ if (args := get_callable_args(self, MultiSet[T])) is not None:
534
+ return list(args)
535
+ raise ExprValueError(self, "MultiSet")
536
+
537
+ __match_args__ = ("value",)
490
538
 
491
539
  @method(preserve=True)
492
540
  def __iter__(self) -> Iterator[T]:
493
- return iter(self.eval())
541
+ return iter(self.value)
494
542
 
495
543
  @method(preserve=True)
496
544
  def __len__(self) -> int:
497
- return len(self.eval())
545
+ return len(self.value)
498
546
 
499
547
  @method(preserve=True)
500
548
  def __contains__(self, key: T) -> bool:
501
- return key in self.eval()
549
+ return key in self.value
502
550
 
503
551
  @method(egg_fn="multiset-of")
504
552
  def __init__(self, *args: T) -> None: ...
@@ -530,30 +578,27 @@ class MultiSet(BuiltinExpr, Generic[T]):
530
578
 
531
579
  class Rational(BuiltinExpr):
532
580
  @method(preserve=True)
581
+ @deprecated("use .value")
533
582
  def eval(self) -> Fraction:
534
- call = _extract_call(self)
535
- if call.callable != InitRef("Rational"):
536
- msg = "Rational can only be initialized with the Rational constructor."
537
- raise BuiltinEvalError(msg)
538
-
539
- def _to_int(e: TypedExprDecl) -> int:
540
- expr = e.expr
541
- if not isinstance(expr, LitDecl):
542
- msg = "Rational can only be initialized with literals"
543
- raise BuiltinEvalError(msg)
544
- assert isinstance(expr.value, int)
545
- return expr.value
546
-
547
- num, den = call.args
548
- return Fraction(_to_int(num), _to_int(den))
583
+ return self.value
584
+
585
+ @method(preserve=True) # type: ignore[misc]
586
+ @property
587
+ def value(self) -> Fraction:
588
+ match get_callable_args(self, Rational):
589
+ case (i64(num), i64(den)):
590
+ return Fraction(num, den)
591
+ raise ExprValueError(self, "Rational(i64(num), i64(den))")
592
+
593
+ __match_args__ = ("value",)
549
594
 
550
595
  @method(preserve=True)
551
596
  def __float__(self) -> float:
552
- return float(self.eval())
597
+ return float(self.value)
553
598
 
554
599
  @method(preserve=True)
555
600
  def __int__(self) -> int:
556
- return int(self.eval())
601
+ return int(self.value)
557
602
 
558
603
  @method(egg_fn="rational")
559
604
  def __init__(self, num: i64Like, den: i64Like) -> None: ...
@@ -617,25 +662,27 @@ class Rational(BuiltinExpr):
617
662
 
618
663
  class BigInt(BuiltinExpr):
619
664
  @method(preserve=True)
665
+ @deprecated("use .value")
620
666
  def eval(self) -> int:
621
- call = _extract_call(self)
622
- if call.callable != ClassMethodRef("BigInt", "from_string"):
623
- msg = "BigInt can only be initialized with the BigInt constructor."
624
- raise BuiltinEvalError(msg)
625
- (s,) = call.args
626
- if not isinstance(s.expr, LitDecl):
627
- msg = "BigInt can only be initialized with literals"
628
- raise BuiltinEvalError(msg)
629
- assert isinstance(s.expr.value, str)
630
- return int(s.expr.value)
667
+ return self.value
668
+
669
+ @method(preserve=True) # type: ignore[misc]
670
+ @property
671
+ def value(self) -> int:
672
+ match get_callable_args(self, BigInt.from_string):
673
+ case (String(s),):
674
+ return int(s)
675
+ raise ExprValueError(self, "BigInt.from_string(String(s))")
676
+
677
+ __match_args__ = ("value",)
631
678
 
632
679
  @method(preserve=True)
633
680
  def __index__(self) -> int:
634
- return self.eval()
681
+ return self.value
635
682
 
636
683
  @method(preserve=True)
637
684
  def __int__(self) -> int:
638
- return self.eval()
685
+ return self.value
639
686
 
640
687
  @method(egg_fn="from-string")
641
688
  @classmethod
@@ -742,34 +789,27 @@ BigIntLike: TypeAlias = BigInt | i64Like
742
789
 
743
790
  class BigRat(BuiltinExpr):
744
791
  @method(preserve=True)
792
+ @deprecated("use .value")
745
793
  def eval(self) -> Fraction:
746
- call = _extract_call(self)
747
- if call.callable != InitRef("BigRat"):
748
- msg = "BigRat can only be initialized with the BigRat constructor."
749
- raise BuiltinEvalError(msg)
750
-
751
- def _to_fraction(e: TypedExprDecl) -> Fraction:
752
- expr = e.expr
753
- if not isinstance(expr, CallDecl) or expr.callable != ClassMethodRef("BigInt", "from_string"):
754
- msg = "BigRat can only be initialized BigInt strings"
755
- raise BuiltinEvalError(msg)
756
- (s,) = expr.args
757
- if not isinstance(s.expr, LitDecl):
758
- msg = "BigInt can only be initialized with literals"
759
- raise BuiltinEvalError(msg)
760
- assert isinstance(s.expr.value, str)
761
- return Fraction(s.expr.value)
762
-
763
- num, den = call.args
764
- return Fraction(_to_fraction(num), _to_fraction(den))
794
+ return self.value
795
+
796
+ @method(preserve=True) # type: ignore[misc]
797
+ @property
798
+ def value(self) -> Fraction:
799
+ match get_callable_args(self, BigRat):
800
+ case (BigInt(num), BigInt(den)):
801
+ return Fraction(num, den)
802
+ raise ExprValueError(self, "BigRat(BigInt(num), BigInt(den))")
803
+
804
+ __match_args__ = ("value",)
765
805
 
766
806
  @method(preserve=True)
767
807
  def __float__(self) -> float:
768
- return float(self.eval())
808
+ return float(self.value)
769
809
 
770
810
  @method(preserve=True)
771
811
  def __int__(self) -> int:
772
- return int(self.eval())
812
+ return int(self.value)
773
813
 
774
814
  @method(egg_fn="bigrat")
775
815
  def __init__(self, num: BigIntLike, den: BigIntLike) -> None: ...
@@ -849,27 +889,32 @@ BigRatLike: TypeAlias = BigRat | Fraction
849
889
 
850
890
  class Vec(BuiltinExpr, Generic[T]):
851
891
  @method(preserve=True)
892
+ @deprecated("use .value")
852
893
  def eval(self) -> tuple[T, ...]:
853
- call = _extract_call(self)
854
- if call.callable == ClassMethodRef("Vec", "empty"):
894
+ return self.value
895
+
896
+ @method(preserve=True) # type: ignore[misc]
897
+ @property
898
+ def value(self) -> tuple[T, ...]:
899
+ if get_callable_args(self, Vec.empty) is not None:
855
900
  return ()
901
+ if (args := get_callable_args(self, Vec[T])) is not None:
902
+ return args
903
+ raise ExprValueError(self, "Vec(*xs) or Vec.empty()")
856
904
 
857
- if call.callable != InitRef("Vec"):
858
- msg = "Vec can only be initialized with the Vec constructor."
859
- raise BuiltinEvalError(msg)
860
- return tuple(cast("T", cast("RuntimeExpr", self).__with_expr__(x)) for x in call.args)
905
+ __match_args__ = ("value",)
861
906
 
862
907
  @method(preserve=True)
863
908
  def __iter__(self) -> Iterator[T]:
864
- return iter(self.eval())
909
+ return iter(self.value)
865
910
 
866
911
  @method(preserve=True)
867
912
  def __len__(self) -> int:
868
- return len(self.eval())
913
+ return len(self.value)
869
914
 
870
915
  @method(preserve=True)
871
916
  def __contains__(self, key: T) -> bool:
872
- return key in self.eval()
917
+ return key in self.value
873
918
 
874
919
  @method(egg_fn="vec-of")
875
920
  def __init__(self, *args: T) -> None: ...
@@ -923,13 +968,20 @@ VecLike: TypeAlias = Vec[T] | tuple[TO, ...] | list[TO]
923
968
 
924
969
  class PyObject(BuiltinExpr):
925
970
  @method(preserve=True)
971
+ @deprecated("use .value")
926
972
  def eval(self) -> object:
973
+ return self.value
974
+
975
+ @method(preserve=True) # type: ignore[misc]
976
+ @property
977
+ def value(self) -> object:
927
978
  expr = cast("RuntimeExpr", self).__egg_typed_expr__.expr
928
979
  if not isinstance(expr, PyObjectDecl):
929
- msg = "PyObject can only be evaluated if it is a PyObject literal"
930
- raise BuiltinEvalError(msg)
980
+ raise ExprValueError(self, "PyObject(x)")
931
981
  return expr.value
932
982
 
983
+ __match_args__ = ("value",)
984
+
933
985
  def __init__(self, value: object) -> None: ...
934
986
 
935
987
  @method(egg_fn="py-from-string")
@@ -1019,6 +1071,23 @@ class UnstableFn(BuiltinExpr, Generic[T, Unpack[TS]]):
1019
1071
  @method(egg_fn="unstable-fn")
1020
1072
  def __init__(self, f, *partial) -> None: ...
1021
1073
 
1074
+ @method(preserve=True)
1075
+ @deprecated("use .value")
1076
+ def eval(self) -> Callable[[Unpack[TS]], T]:
1077
+ return self.value
1078
+
1079
+ @method(preserve=True) # type: ignore[prop-decorator]
1080
+ @property
1081
+ def value(self) -> Callable[[Unpack[TS]], T]:
1082
+ """
1083
+ If this is a constructor, returns either the callable directly or a `functools.partial` function if args are provided.
1084
+ """
1085
+ if (fn := get_literal_value(self)) is not None:
1086
+ return fn
1087
+ raise ExprValueError(self, "UnstableFn(f, *args)")
1088
+
1089
+ __match_args__ = ("value",)
1090
+
1022
1091
  @method(egg_fn="unstable-app")
1023
1092
  def __call__(self, *args: Unpack[TS]) -> T: ...
1024
1093
 
@@ -1029,57 +1098,36 @@ converter(RuntimeFunction, UnstableFn, UnstableFn)
1029
1098
  converter(partial, UnstableFn, lambda p: UnstableFn(p.func, *p.args))
1030
1099
 
1031
1100
 
1032
- def _convert_function(a: FunctionType) -> UnstableFn:
1101
+ def _convert_function(fn: FunctionType) -> UnstableFn:
1033
1102
  """
1034
- Converts a function type to an unstable function
1103
+ Converts a function type to an unstable function. This function will be an anon function in egglog.
1035
1104
 
1036
- Would just be UnstableFn(function(a)) but we have to look for any nonlocals and globals
1037
- which are runtime expressions with `var`s in them and add them as args to the function
1105
+ Would just be UnstableFn(function(a)) but we have to account for unbound vars within the body.
1106
+
1107
+ This means that we have to turn all of those unbound vars into args to the function, and then
1108
+ partially apply them, alongside creating a default rewrite for the function.
1038
1109
  """
1039
- # Update annotations of a to be the type we are trying to convert to
1040
- return_tp, *arg_tps = get_type_args()
1041
- a.__annotations__ = {
1042
- "return": return_tp,
1043
- # The first varnames should always be the arg names
1044
- **dict(zip(a.__code__.co_varnames, arg_tps, strict=False)),
1045
- }
1046
- # Modify name to make it unique
1047
- # a.__name__ = f"{a.__name__} {hash(a.__code__)}"
1048
- transformed_fn = functionalize(a, value_to_annotation)
1049
- assert isinstance(transformed_fn, partial)
1050
- return UnstableFn(
1051
- function(ruleset=get_current_ruleset(), use_body_as_name=True, subsume=True)(transformed_fn.func),
1052
- *transformed_fn.args,
1110
+ decls = Declarations()
1111
+ return_type, *arg_types = [resolve_type_annotation_mutate(decls, tp) for tp in get_type_args()]
1112
+ arg_names = [p.name for p in signature(fn).parameters.values()]
1113
+ arg_decls = [
1114
+ TypedExprDecl(tp.to_just(), UnboundVarDecl(name)) for name, tp in zip(arg_names, arg_types, strict=True)
1115
+ ]
1116
+ res = resolve_literal(
1117
+ return_type, fn(*(RuntimeExpr.__from_values__(decls, a) for a in arg_decls)), Thunk.value(decls)
1053
1118
  )
1119
+ res_expr = res.__egg_typed_expr__
1120
+ decls |= res
1121
+ # these are all the args that appear in the body that are not bound by the args of the function
1122
+ unbound_vars = list(collect_unbound_vars(res_expr) - set(arg_decls))
1123
+ # prefix the args with them
1124
+ fn_ref = UnnamedFunctionRef(tuple(unbound_vars + arg_decls), res_expr)
1125
+ rewrite_decl = DefaultRewriteDecl(fn_ref, res_expr.expr, subsume=True)
1126
+ ruleset_decls = _add_default_rewrite_inner(decls, rewrite_decl, get_current_ruleset())
1127
+ ruleset_decls |= res
1054
1128
 
1055
-
1056
- def value_to_annotation(a: object) -> type | None:
1057
- # only lift runtime expressions (which could contain vars) not any other nonlocals/globals we use in the function
1058
- if not isinstance(a, RuntimeExpr):
1059
- return None
1060
- return cast("type", RuntimeClass(Thunk.value(a.__egg_decls__), a.__egg_typed_expr__.tp.to_var()))
1129
+ fn = RuntimeFunction(Thunk.value(decls), Thunk.value(fn_ref))
1130
+ return UnstableFn(fn, *(RuntimeExpr.__from_values__(decls, v) for v in unbound_vars))
1061
1131
 
1062
1132
 
1063
1133
  converter(FunctionType, UnstableFn, _convert_function)
1064
-
1065
-
1066
- def _extract_lit(e: BaseExpr) -> LitType:
1067
- """
1068
- Special case extracting literals to make this faster by using termdag directly.
1069
- """
1070
- expr = cast("RuntimeExpr", e).__egg_typed_expr__.expr
1071
- if not isinstance(expr, LitDecl):
1072
- msg = "Expected a literal"
1073
- raise BuiltinEvalError(msg)
1074
- return expr.value
1075
-
1076
-
1077
- def _extract_call(e: BaseExpr) -> CallDecl:
1078
- """
1079
- Extracts the call form of an expression
1080
- """
1081
- expr = cast("RuntimeExpr", e).__egg_typed_expr__.expr
1082
- if not isinstance(expr, CallDecl):
1083
- msg = "Expected a call expression"
1084
- raise BuiltinEvalError(msg)
1085
- return expr