sonolus.py 0.3.4__py3-none-any.whl → 0.4.1__py3-none-any.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 sonolus.py might be problematic. Click here for more details.

Files changed (64) hide show
  1. sonolus/backend/excepthook.py +30 -0
  2. sonolus/backend/finalize.py +15 -1
  3. sonolus/backend/ops.py +4 -0
  4. sonolus/backend/optimize/allocate.py +5 -5
  5. sonolus/backend/optimize/constant_evaluation.py +124 -19
  6. sonolus/backend/optimize/copy_coalesce.py +15 -12
  7. sonolus/backend/optimize/dead_code.py +7 -6
  8. sonolus/backend/optimize/dominance.py +2 -2
  9. sonolus/backend/optimize/flow.py +54 -8
  10. sonolus/backend/optimize/inlining.py +137 -30
  11. sonolus/backend/optimize/liveness.py +2 -2
  12. sonolus/backend/optimize/optimize.py +15 -1
  13. sonolus/backend/optimize/passes.py +11 -3
  14. sonolus/backend/optimize/simplify.py +137 -8
  15. sonolus/backend/optimize/ssa.py +47 -13
  16. sonolus/backend/place.py +5 -4
  17. sonolus/backend/utils.py +44 -16
  18. sonolus/backend/visitor.py +288 -17
  19. sonolus/build/cli.py +47 -19
  20. sonolus/build/compile.py +12 -5
  21. sonolus/build/engine.py +70 -1
  22. sonolus/build/level.py +3 -3
  23. sonolus/build/project.py +2 -2
  24. sonolus/script/archetype.py +12 -9
  25. sonolus/script/array.py +23 -18
  26. sonolus/script/array_like.py +26 -29
  27. sonolus/script/bucket.py +1 -1
  28. sonolus/script/containers.py +22 -26
  29. sonolus/script/debug.py +20 -43
  30. sonolus/script/effect.py +1 -1
  31. sonolus/script/globals.py +3 -3
  32. sonolus/script/instruction.py +2 -2
  33. sonolus/script/internal/builtin_impls.py +155 -28
  34. sonolus/script/internal/constant.py +13 -3
  35. sonolus/script/internal/context.py +46 -15
  36. sonolus/script/internal/impl.py +9 -3
  37. sonolus/script/internal/introspection.py +8 -1
  38. sonolus/script/internal/native.py +2 -2
  39. sonolus/script/internal/range.py +8 -11
  40. sonolus/script/internal/simulation_context.py +1 -1
  41. sonolus/script/internal/transient.py +2 -2
  42. sonolus/script/internal/value.py +41 -3
  43. sonolus/script/interval.py +13 -13
  44. sonolus/script/iterator.py +53 -107
  45. sonolus/script/level.py +2 -2
  46. sonolus/script/maybe.py +241 -0
  47. sonolus/script/num.py +29 -14
  48. sonolus/script/options.py +1 -1
  49. sonolus/script/particle.py +1 -1
  50. sonolus/script/project.py +24 -5
  51. sonolus/script/quad.py +15 -15
  52. sonolus/script/record.py +48 -44
  53. sonolus/script/runtime.py +22 -18
  54. sonolus/script/sprite.py +1 -1
  55. sonolus/script/stream.py +66 -82
  56. sonolus/script/transform.py +35 -34
  57. sonolus/script/values.py +10 -10
  58. sonolus/script/vec.py +21 -18
  59. {sonolus_py-0.3.4.dist-info → sonolus_py-0.4.1.dist-info}/METADATA +1 -1
  60. sonolus_py-0.4.1.dist-info/RECORD +93 -0
  61. sonolus_py-0.3.4.dist-info/RECORD +0 -92
  62. {sonolus_py-0.3.4.dist-info → sonolus_py-0.4.1.dist-info}/WHEEL +0 -0
  63. {sonolus_py-0.3.4.dist-info → sonolus_py-0.4.1.dist-info}/entry_points.txt +0 -0
  64. {sonolus_py-0.3.4.dist-info → sonolus_py-0.4.1.dist-info}/licenses/LICENSE +0 -0
sonolus/script/debug.py CHANGED
@@ -4,18 +4,9 @@ from typing import Any, Literal, Never
4
4
 
5
5
  from sonolus.backend.mode import Mode
6
6
  from sonolus.backend.ops import Op
7
- from sonolus.backend.optimize.constant_evaluation import SparseConditionalConstantPropagation
8
- from sonolus.backend.optimize.copy_coalesce import CopyCoalesce
9
- from sonolus.backend.optimize.dead_code import (
10
- AdvancedDeadCodeElimination,
11
- DeadCodeElimination,
12
- UnreachableCodeElimination,
13
- )
14
7
  from sonolus.backend.optimize.flow import cfg_to_mermaid
15
- from sonolus.backend.optimize.inlining import InlineVars
16
- from sonolus.backend.optimize.passes import CompilerPass, run_passes
17
- from sonolus.backend.optimize.simplify import CoalesceFlow, NormalizeSwitch, RewriteToSwitch
18
- from sonolus.backend.optimize.ssa import FromSSA, ToSSA
8
+ from sonolus.backend.optimize.passes import CompilerPass, OptimizerConfig, run_passes
9
+ from sonolus.backend.optimize.simplify import RenumberVars
19
10
  from sonolus.script.internal.context import GlobalContextState, ReadOnlyMemory, ctx, set_ctx
20
11
  from sonolus.script.internal.impl import meta_fn, validate_value
21
12
  from sonolus.script.internal.native import native_function
@@ -26,13 +17,13 @@ debug_log_callback = ContextVar[Callable[[Num], None]]("debug_log_callback")
26
17
 
27
18
 
28
19
  @meta_fn
29
- def error(message: str | None = None) -> Never:
20
+ def error(message: str | None = None) -> Never: # type: ignore
30
21
  """Raise an error.
31
22
 
32
23
  This function is used to raise an error during runtime.
33
24
  When this happens, the game will pause in debug mode. The current callback will also immediately return 0.
34
25
  """
35
- message = validate_value(message)._as_py_() if message is not None else "Error"
26
+ message = validate_value(message)._as_py_() or "Error" # type: ignore
36
27
  if not isinstance(message, str):
37
28
  raise ValueError("Expected a string")
38
29
  if ctx():
@@ -50,7 +41,7 @@ def static_error(message: str | None = None) -> Never:
50
41
  This function is used to raise an error during compile-time if the compiler cannot guarantee that
51
42
  this function will not be called during runtime.
52
43
  """
53
- message = validate_value(message)._as_py_() if message is not None else "Error"
44
+ message = validate_value(message)._as_py_() or "Error" # type: ignore
54
45
  if not isinstance(message, str):
55
46
  raise ValueError("Expected a string")
56
47
  raise RuntimeError(message)
@@ -60,7 +51,7 @@ def static_error(message: str | None = None) -> Never:
60
51
  def debug_log(value: int | float | bool):
61
52
  """Log a value in debug mode."""
62
53
  if debug_log_callback.get(None):
63
- return debug_log_callback.get()(value)
54
+ return debug_log_callback.get()(value) # type: ignore
64
55
  else:
65
56
  return _debug_log(value)
66
57
 
@@ -91,7 +82,7 @@ def assert_false(value: int | float | bool, message: str | None = None):
91
82
 
92
83
  @meta_fn
93
84
  def assert_unreachable(message: str | None = None) -> Never:
94
- message = validate_value(message)._as_py_() or "Unreachable code reached"
85
+ message = validate_value(message)._as_py_() or "Unreachable code reached" # type: ignore
95
86
  raise RuntimeError(message)
96
87
 
97
88
 
@@ -108,43 +99,29 @@ def visualize_cfg(
108
99
  /,
109
100
  *,
110
101
  mode: Mode = Mode.PLAY,
102
+ callback: str = "",
111
103
  archetype: type | None = None,
112
- archetypes: list[type] | None,
113
- passes: Sequence[CompilerPass] | Literal["minimal", "basic", "standard"] = "basic",
104
+ archetypes: list[type] | None = None,
105
+ passes: Sequence[CompilerPass] | Literal["minimal", "fast", "standard"] = "fast",
114
106
  ) -> str:
107
+ from sonolus.backend.optimize.optimize import FAST_PASSES, MINIMAL_PASSES, STANDARD_PASSES
115
108
  from sonolus.build.compile import callback_to_cfg
116
109
 
117
110
  match passes:
118
111
  case "minimal":
119
112
  passes = [
120
- CoalesceFlow(),
113
+ *MINIMAL_PASSES[:-1],
114
+ RenumberVars(),
121
115
  ]
122
- case "basic":
116
+ case "fast":
123
117
  passes = [
124
- CoalesceFlow(),
125
- UnreachableCodeElimination(),
126
- AdvancedDeadCodeElimination(),
127
- CoalesceFlow(),
118
+ *FAST_PASSES[:-1],
119
+ RenumberVars(),
128
120
  ]
129
121
  case "standard":
130
122
  passes = [
131
- CoalesceFlow(),
132
- UnreachableCodeElimination(),
133
- DeadCodeElimination(),
134
- ToSSA(),
135
- SparseConditionalConstantPropagation(),
136
- UnreachableCodeElimination(),
137
- DeadCodeElimination(),
138
- CoalesceFlow(),
139
- InlineVars(),
140
- DeadCodeElimination(),
141
- RewriteToSwitch(),
142
- FromSSA(),
143
- CoalesceFlow(),
144
- CopyCoalesce(),
145
- AdvancedDeadCodeElimination(),
146
- CoalesceFlow(),
147
- NormalizeSwitch(),
123
+ *STANDARD_PASSES[:-1],
124
+ RenumberVars(),
148
125
  ]
149
126
 
150
127
  global_state = GlobalContextState(
@@ -153,8 +130,8 @@ def visualize_cfg(
153
130
  ReadOnlyMemory(),
154
131
  )
155
132
 
156
- cfg = callback_to_cfg(global_state, fn, "", archetype=archetype)
157
- cfg = run_passes(cfg, passes)
133
+ cfg = callback_to_cfg(global_state, fn, callback, archetype=archetype) # type: ignore
134
+ cfg = run_passes(cfg, passes, OptimizerConfig(mode=mode))
158
135
  return cfg_to_mermaid(cfg)
159
136
 
160
137
 
sonolus/script/effect.py CHANGED
@@ -134,7 +134,7 @@ def effect(name: str) -> Any:
134
134
  return EffectInfo(name)
135
135
 
136
136
 
137
- type Effects = NewType("Effects", Any)
137
+ type Effects = NewType("Effects", Any) # type: ignore
138
138
 
139
139
 
140
140
  @dataclass_transform()
sonolus/script/globals.py CHANGED
@@ -39,7 +39,7 @@ class _GlobalField(SonolusDescriptor):
39
39
  if not ctx():
40
40
  raise RuntimeError("Global field access outside of compilation")
41
41
  base = ctx().get_global_base(info)
42
- return self.type._from_place_(base.add_offset(self.offset))._get_()
42
+ return self.type._from_place_(base.add_offset(self.offset))._get_readonly_()
43
43
 
44
44
  def __set__(self, instance, value):
45
45
  from sonolus.script.internal.context import ctx
@@ -96,8 +96,8 @@ def _create_global(cls: type, blocks: dict[Mode, Block], offset: int | None):
96
96
  type_ = validate_concrete_type(annotation)
97
97
  setattr(cls, name, _GlobalField(name, type_, i, field_offset))
98
98
  field_offset += type_._size_()
99
- cls._global_info_ = _GlobalInfo(cls.__name__, field_offset, blocks, offset)
100
- cls._is_comptime_value_ = True
99
+ cls._global_info_ = _GlobalInfo(cls.__name__, field_offset, blocks, offset) # type: ignore
100
+ cls._is_comptime_value_ = True # type: ignore
101
101
  return cls()
102
102
 
103
103
 
@@ -70,8 +70,8 @@ def instruction_icon(name: str) -> Any:
70
70
  return _InstructionIconInfo(name=name)
71
71
 
72
72
 
73
- type TutorialInstructions = NewType("TutorialInstructions", Any)
74
- type TutorialInstructionIcons = NewType("TutorialInstructionIcons", Any)
73
+ type TutorialInstructions = NewType("TutorialInstructions", Any) # type: ignore
74
+ type TutorialInstructionIcons = NewType("TutorialInstructionIcons", Any) # type: ignore
75
75
 
76
76
 
77
77
  @dataclass_transform()
@@ -1,12 +1,12 @@
1
- from collections.abc import Iterable
2
- from typing import overload
3
-
1
+ from sonolus.backend.ops import Op
4
2
  from sonolus.script.array import Array
5
3
  from sonolus.script.array_like import ArrayLike
4
+ from sonolus.script.debug import error
6
5
  from sonolus.script.internal.context import ctx
7
6
  from sonolus.script.internal.dict_impl import DictImpl
8
7
  from sonolus.script.internal.impl import meta_fn, validate_value
9
8
  from sonolus.script.internal.math_impls import MATH_BUILTIN_IMPLS, _trunc
9
+ from sonolus.script.internal.native import native_function
10
10
  from sonolus.script.internal.random import RANDOM_BUILTIN_IMPLS
11
11
  from sonolus.script.internal.range import Range
12
12
  from sonolus.script.internal.tuple_impl import TupleImpl
@@ -21,6 +21,8 @@ from sonolus.script.iterator import (
21
21
  )
22
22
  from sonolus.script.num import Num, _is_num
23
23
 
24
+ _empty = object()
25
+
24
26
 
25
27
  @meta_fn
26
28
  def _isinstance(value, type_):
@@ -44,7 +46,7 @@ def _len(value):
44
46
  value = validate_value(value)
45
47
  if not hasattr(value, "__len__"):
46
48
  raise TypeError(f"object of type '{type(value).__name__}' has no len()")
47
- return compile_and_call(value.__len__)
49
+ return compile_and_call(value.__len__) # type: ignore
48
50
 
49
51
 
50
52
  @meta_fn
@@ -59,7 +61,7 @@ def _enumerate(iterable, start=0):
59
61
  elif isinstance(iterable, ArrayLike):
60
62
  return compile_and_call(iterable._enumerate_, start)
61
63
  else:
62
- iterator = compile_and_call(iterable.__iter__)
64
+ iterator = compile_and_call(iterable.__iter__) # type: ignore
63
65
  if not isinstance(iterator, SonolusIterator):
64
66
  raise TypeError("Only subclasses of SonolusIterator are supported as iterators")
65
67
  return _Enumerator(0, start, iterator)
@@ -104,25 +106,20 @@ def _abs(value):
104
106
  value = validate_value(value)
105
107
  if not hasattr(value, "__abs__"):
106
108
  raise TypeError(f"bad operand type for abs(): '{type(value).__name__}'")
107
- return compile_and_call(value.__abs__)
109
+ return compile_and_call(value.__abs__) # type: ignore
108
110
 
109
111
 
110
112
  def _identity(value):
111
113
  return value
112
114
 
113
115
 
114
- @overload
115
- def _max[T](iterable: Iterable[T], *, key: callable = ...) -> T: ...
116
-
117
-
118
- @overload
119
- def _max[T](a: T, b: T, *args: T, key: callable = ...) -> T: ...
120
-
121
-
122
116
  @meta_fn
123
- def _max(*args, key: callable = _identity):
117
+ def _max(*args, default=_empty, key=None):
124
118
  from sonolus.backend.visitor import compile_and_call
125
119
 
120
+ if key is None:
121
+ key = _identity
122
+
126
123
  args = tuple(validate_value(arg) for arg in args)
127
124
  if len(args) == 0:
128
125
  raise ValueError("Expected at least one argument to max")
@@ -131,40 +128,91 @@ def _max(*args, key: callable = _identity):
131
128
  if isinstance(iterable, ArrayLike):
132
129
  return compile_and_call(iterable._max_, key=key)
133
130
  elif isinstance(iterable, TupleImpl) and all(_is_num(v) for v in iterable.value):
131
+ if len(iterable.value) == 0:
132
+ if default is not _empty:
133
+ return default
134
+ raise ValueError("max() arg is an empty sequence")
134
135
  return compile_and_call(Array(*iterable.value)._max_, key=key)
136
+ elif isinstance(iterable, SonolusIterator):
137
+ if not (default is _empty or Num._accepts_(default)):
138
+ raise TypeError("default argument must be a number")
139
+ return compile_and_call(
140
+ _max_num_iterator,
141
+ iterable,
142
+ Num._accept_(default) if default is not _empty else None,
143
+ key=key if key is not _identity else None,
144
+ )
135
145
  else:
136
146
  raise TypeError(f"Unsupported type: {type(iterable)} for max")
137
147
  else:
148
+ if default is not _empty:
149
+ raise TypeError("default argument is not supported for max with multiple arguments")
138
150
  if not all(_is_num(arg) for arg in args):
139
151
  raise TypeError("Arguments to max must be numbers")
140
152
  if ctx():
141
- result = compile_and_call(_max2, args[0], args[1], key=key)
153
+ result = _max2(args[0], args[1], key=key)
142
154
  for arg in args[2:]:
143
- result = compile_and_call(_max2, result, arg, key=key)
155
+ result = _max2(result, arg, key=key)
144
156
  return result
145
157
  else:
146
158
  return max(arg._as_py_() for arg in args)
147
159
 
148
160
 
149
161
  def _max2(a, b, key=_identity):
150
- if key(a) > key(b):
162
+ from sonolus.backend.visitor import compile_and_call
163
+
164
+ a = validate_value(a)
165
+ b = validate_value(b)
166
+ if _is_num(a) and _is_num(b) and key == _identity:
167
+ return compile_and_call(_max2_num, a, b)
168
+ return compile_and_call(_max2_generic, a, b, key=key)
169
+
170
+
171
+ @native_function(Op.Max)
172
+ def _max2_num(a, b):
173
+ if a > b:
151
174
  return a
152
175
  else:
153
176
  return b
154
177
 
155
178
 
156
- @overload
157
- def _min[T](iterable: Iterable[T], *, key: callable = ...) -> T: ...
179
+ def _max2_generic(a, b, key=_identity):
180
+ if key(a) > key(b):
181
+ return a
182
+ else:
183
+ return b
158
184
 
159
185
 
160
- @overload
161
- def _min[T](a: T, b: T, *args: T, key: callable = ...) -> T: ...
186
+ def _max_num_iterator(iterable, default, key):
187
+ iterator = iterable.__iter__() # noqa: PLC2801
188
+ initial = iterator.next()
189
+ if initial.is_nothing:
190
+ assert default is not None
191
+ return default
192
+ if key is not None:
193
+ result = initial.get_unsafe()
194
+ best_key = key(result)
195
+ for value in iterator:
196
+ new_key = key(value)
197
+ if new_key > best_key:
198
+ result = value
199
+ best_key = new_key
200
+ return result
201
+ else:
202
+ result = initial.get_unsafe()
203
+ for value in iterator:
204
+ if value > result: # noqa: PLR1730
205
+ result = value
206
+ return result
162
207
 
163
208
 
164
209
  @meta_fn
165
- def _min(*args, key: callable = _identity):
210
+ def _min(*args, default=_empty, key=None):
166
211
  from sonolus.backend.visitor import compile_and_call
167
212
 
213
+ if key is None:
214
+ key = _identity
215
+
168
216
  args = tuple(validate_value(arg) for arg in args)
169
217
  if len(args) == 0:
170
218
  raise ValueError("Expected at least one argument to min")
@@ -173,34 +221,92 @@ def _min(*args, key: callable = _identity):
173
221
  if isinstance(iterable, ArrayLike):
174
222
  return compile_and_call(iterable._min_, key=key)
175
223
  elif isinstance(iterable, TupleImpl) and all(_is_num(v) for v in iterable.value):
224
+ if len(iterable.value) == 0:
225
+ if default is not _empty:
226
+ return default
227
+ raise ValueError("min() arg is an empty sequence")
176
228
  return compile_and_call(Array(*iterable.value)._min_, key=key)
229
+ elif isinstance(iterable, SonolusIterator):
230
+ if not (default is _empty or Num._accepts_(default)):
231
+ raise TypeError("default argument must be a number")
232
+ return compile_and_call(
233
+ _min_num_iterator,
234
+ iterable,
235
+ Num._accept_(default) if default is not _empty else None,
236
+ key=key if key is not _identity else None,
237
+ )
177
238
  else:
178
239
  raise TypeError(f"Unsupported type: {type(iterable)} for min")
179
240
  else:
241
+ if default is not _empty:
242
+ raise TypeError("default argument is not supported for min with multiple arguments")
180
243
  if not all(_is_num(arg) for arg in args):
181
244
  raise TypeError("Arguments to min must be numbers")
182
245
  if ctx():
183
- result = compile_and_call(_min2, args[0], args[1], key=key)
246
+ result = _min2(args[0], args[1], key=key)
184
247
  for arg in args[2:]:
185
- result = compile_and_call(_min2, result, arg, key=key)
248
+ result = _min2(result, arg, key=key)
186
249
  return result
187
250
  else:
188
251
  return min(arg._as_py_() for arg in args)
189
252
 
190
253
 
191
254
  def _min2(a, b, key=_identity):
255
+ from sonolus.backend.visitor import compile_and_call
256
+
257
+ a = validate_value(a)
258
+ b = validate_value(b)
259
+ if _is_num(a) and _is_num(b) and key == _identity:
260
+ return compile_and_call(_min2_num, a, b)
261
+ return compile_and_call(_min2_generic, a, b, key=key)
262
+
263
+
264
+ @native_function(Op.Min)
265
+ def _min2_num(a, b):
266
+ if a < b:
267
+ return a
268
+ else:
269
+ return b
270
+
271
+
272
+ def _min2_generic(a, b, key=_identity):
192
273
  if key(a) < key(b):
193
274
  return a
194
275
  else:
195
276
  return b
196
277
 
197
278
 
279
+ def _min_num_iterator(iterable, default, key):
280
+ iterator = iterable.__iter__() # noqa: PLC2801
281
+ initial = iterator.next()
282
+ if initial.is_nothing:
283
+ assert default is not None
284
+ return default
285
+ if key is not None:
286
+ result = initial.get_unsafe()
287
+ best_key = key(result)
288
+ for value in iterator:
289
+ new_key = key(value)
290
+ if new_key < best_key:
291
+ result = value
292
+ best_key = new_key
293
+ return result
294
+ else:
295
+ result = initial.get_unsafe()
296
+ for value in iterator:
297
+ if value < result: # noqa: PLR1730
298
+ result = value
299
+ return result
300
+
301
+
198
302
  @meta_fn
199
303
  def _callable(value):
200
304
  return callable(value)
201
305
 
202
306
 
203
307
  def _map(fn, iterable, *iterables):
308
+ if len(iterables) == 0:
309
+ return _MappingIterator(fn, iterable.__iter__()) # noqa: PLC2801
204
310
  return _MappingIterator(lambda args: fn(*args), zip(iterable, *iterables)) # noqa: B905
205
311
 
206
312
 
@@ -234,9 +340,9 @@ def _bool(value=False):
234
340
  return False
235
341
 
236
342
 
237
- _int._type_mapping_ = Num
238
- _float._type_mapping_ = Num
239
- _bool._type_mapping_ = Num
343
+ _int._type_mapping_ = Num # type: ignore
344
+ _float._type_mapping_ = Num # type: ignore
345
+ _bool._type_mapping_ = Num # type: ignore
240
346
 
241
347
 
242
348
  def _any(iterable):
@@ -253,12 +359,31 @@ def _all(iterable):
253
359
  return True
254
360
 
255
361
 
362
+ def _sum(iterable, /, start=0):
363
+ for value in iterable:
364
+ start += value
365
+ return start
366
+
367
+
368
+ def _next(iterator):
369
+ assert isinstance(iterator, SonolusIterator)
370
+ value = iterator.next()
371
+ if value.is_some:
372
+ return value.get_unsafe()
373
+ error("Iterator has been exhausted")
374
+
375
+
376
+ def _iter(iterable):
377
+ return iterable.__iter__() # type: ignore # noqa: PLC2801
378
+
379
+
256
380
  # classmethod, property, staticmethod are supported as decorators, but not within functions
257
381
 
258
382
  BUILTIN_IMPLS = {
259
383
  id(abs): _abs,
260
384
  id(all): _all,
261
385
  id(any): _any,
386
+ id(sum): _sum,
262
387
  id(bool): _bool,
263
388
  id(callable): _callable,
264
389
  id(enumerate): _enumerate,
@@ -266,10 +391,12 @@ BUILTIN_IMPLS = {
266
391
  id(float): _float,
267
392
  id(int): _int,
268
393
  id(isinstance): _isinstance,
394
+ id(iter): _iter,
269
395
  id(len): _len,
270
396
  id(map): _map,
271
397
  id(max): _max,
272
398
  id(min): _min,
399
+ id(next): _next,
273
400
  id(range): Range,
274
401
  id(reversed): _reversed,
275
402
  id(zip): _zip,
@@ -48,8 +48,8 @@ class ConstantValue(Value):
48
48
  class Parameterized(cls):
49
49
  _value = (parameter,)
50
50
 
51
- Parameterized.__name__ = f"{parameter}"
52
- Parameterized.__qualname__ = f"{parameter}"
51
+ Parameterized.__name__ = f"Const[{object.__repr__(parameter)}]" # noqa: PLC2801
52
+ Parameterized.__qualname__ = Parameterized.__name__
53
53
  Parameterized.__module__ = cls.__module__
54
54
  Parameterized.instance = object.__new__(Parameterized)
55
55
  return Parameterized
@@ -113,7 +113,7 @@ class ConstantValue(Value):
113
113
  if value is not self:
114
114
  raise ValueError(f"{type(self).__name__} is immutable")
115
115
 
116
- def _copy_from_(self, value: Self):
116
+ def _copy_from_(self, value: Any):
117
117
  if value is not self:
118
118
  raise ValueError(f"{type(self).__name__} is immutable")
119
119
 
@@ -143,3 +143,13 @@ class ConstantValue(Value):
143
143
 
144
144
  class BasicConstantValue(ConstantValue):
145
145
  """For constants without any special behavior."""
146
+
147
+
148
+ class TypingSpecialFormConstant(ConstantValue):
149
+ """For constants that are typing special forms that have a [] operator."""
150
+
151
+ @meta_fn
152
+ def __getitem__(self, item: Any) -> Self:
153
+ if not item._is_py_():
154
+ raise TypeError(f"Invalid value for type parameter: {item}")
155
+ return self.value()[item._as_py_()]