Skip to content

analysis

Re-export the semantic-analysis APIs, semantic-contract types, and sidecar metadata used by hosts, tests, and backend lowering.

Modules:

Classes:

Functions:

ClassHeaderFieldKind

Bases: str, Enum

Name the reserved object-header slots that later lowering and dispatch phases can populate without changing the class object layout.

ClassInitializationSourceKind

Bases: str, Enum

Distinguish declaration-provided field initializers from implicit default construction values.

ClassMemberKind

Bases: str, Enum

ClassMemberResolutionKind

Bases: str, Enum

Distinguish members declared locally, members that override inherited declarations, and members inherited directly from the resolved MRO.

ClassObjectRepresentationKind

Bases: str, Enum

Distinguish whether class values are modeled as pointers or values.

CollectionMethodKind

Bases: str, Enum

CompilationSession dataclass

CompilationSession(
    root: ParsedModule,
    resolver: ImportResolver,
    modules: dict[ModuleKey, ParsedModule] = dict(),
    graph: dict[ModuleKey, set[ModuleKey]] = dict(),
    load_order: list[ModuleKey] = list(),
    diagnostics: DiagnosticBag = DiagnosticBag(),
    visible_bindings: dict[
        ModuleKey, dict[str, SemanticBinding]
    ] = dict(),
    _resolution_cache: dict[
        tuple[ModuleKey, str], ParsedModule | None
    ] = dict(),
    _probe_cache: dict[
        tuple[ModuleKey, str], ParsedModule | None
    ] = dict(),
)

Own the loaded module graph and cross-module binding state that analysis and lowering share for one compilation. attributes: root: type: ParsedModule resolver: type: ImportResolver modules: type: dict[ModuleKey, ParsedModule] graph: type: dict[ModuleKey, set[ModuleKey]] load_order: type: list[ModuleKey] diagnostics: type: DiagnosticBag visible_bindings: type: dict[ModuleKey, dict[str, SemanticBinding]] _resolution_cache: type: dict[tuple[ModuleKey, str], ParsedModule | None] _probe_cache: type: dict[tuple[ModuleKey, str], ParsedModule | None]

Methods:

expand_graph

expand_graph() -> None

Walk top-level imports from the root module, load every reachable dependency, and reject cycles.

Source code in packages/irx/src/irx/analysis/session.py
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
def expand_graph(self) -> None:
    """
    title: Expand the reachable import graph from the root module.
    summary: >-
      Walk top-level imports from the root module, load every reachable
      dependency, and reject cycles.
    """
    self.load_order.clear()
    temporary: list[ModuleKey] = []
    temporary_lookup: set[ModuleKey] = set()
    permanent: set[ModuleKey] = set()
    importable_names: dict[ModuleKey, set[str]] = {}

    def dfs(module_key: ModuleKey) -> set[str]:
        """
        title: Visit one reachable module during graph expansion.
        summary: >-
          Depth-first walk one module, record its outgoing edges, append it
          to the stable load order after its dependencies, and track which
          names later from-import statements may bind directly from that
          module.
        parameters:
          module_key:
            type: ModuleKey
        returns:
          type: set[str]
        """
        if module_key in permanent:
            return importable_names[module_key]
        if module_key in temporary_lookup:
            cycle_start = temporary.index(module_key)
            cycle_path = [*temporary[cycle_start:], module_key]
            cycle_str = " -> ".join(str(item) for item in cycle_path)
            self.diagnostics.add(
                f"Cyclic import detected: {cycle_str}",
                node=self.modules[module_key].ast,
                module_key=module_key,
            )
            return importable_names.get(module_key, set())

        temporary.append(module_key)
        temporary_lookup.add(module_key)

        parsed_module = self.modules[module_key]
        dependencies: list[ModuleKey] = []
        module_importable_names = importable_names.setdefault(
            module_key,
            _declared_importable_names(parsed_module.ast),
        )
        for node in parsed_module.ast.nodes:
            if isinstance(node, astx.ImportStmt):
                for alias in node.names:
                    resolved = self.resolve_import_specifier(
                        module_key,
                        node,
                        alias.name,
                    )
                    if resolved is None:
                        continue
                    self.graph.setdefault(module_key, set()).add(
                        resolved.key
                    )
                    dependencies.append(resolved.key)
            elif isinstance(node, astx.ImportFromStmt):
                resolved_parent = self.resolve_import_specifier(
                    module_key,
                    node,
                    _module_import_specifier(node),
                )
                if resolved_parent is None:
                    continue
                self.graph.setdefault(module_key, set()).add(
                    resolved_parent.key
                )
                dependencies.append(resolved_parent.key)
                parent_importable_names = dfs(resolved_parent.key)

                for alias in node.names:
                    if alias.name == "*":
                        continue

                    local_name = alias.asname or alias.name
                    if alias.name in parent_importable_names:
                        module_importable_names.add(local_name)
                        continue

                    resolved_child = self.probe_import_specifier(
                        module_key,
                        node,
                        f"{resolved_parent.key}.{alias.name}",
                    )
                    if resolved_child is None:
                        continue
                    self.graph.setdefault(module_key, set()).add(
                        resolved_child.key
                    )
                    dependencies.append(resolved_child.key)

        for dependency_key in dependencies:
            dfs(dependency_key)

        temporary.pop()
        temporary_lookup.remove(module_key)
        permanent.add(module_key)
        self.load_order.append(module_key)
        return module_importable_names

    dfs(self.root.key)

module

module(module_key: ModuleKey) -> ParsedModule

Look up a previously-registered parsed module by its canonical host key. parameters: module_key: type: ModuleKey returns: type: ParsedModule

Source code in packages/irx/src/irx/analysis/session.py
144
145
146
147
148
149
150
151
152
153
154
155
156
def module(self, module_key: ModuleKey) -> ParsedModule:
    """
    title: Return a parsed module by key.
    summary: >-
      Look up a previously-registered parsed module by its canonical host
      key.
    parameters:
      module_key:
        type: ModuleKey
    returns:
      type: ParsedModule
    """
    return self.modules[module_key]

ordered_modules

ordered_modules() -> list[ParsedModule]

Materialize the dependency-ordered module list used by later semantic and lowering passes. returns: type: list[ParsedModule]

Source code in packages/irx/src/irx/analysis/session.py
158
159
160
161
162
163
164
165
166
167
def ordered_modules(self) -> list[ParsedModule]:
    """
    title: Return parsed modules in stable dependency order.
    summary: >-
      Materialize the dependency-ordered module list used by later semantic
      and lowering passes.
    returns:
      type: list[ParsedModule]
    """
    return [self.modules[module_key] for module_key in self.load_order]

probe_import_specifier

probe_import_specifier(
    requesting_module_key: ModuleKey,
    import_node: ImportStmt | ImportFromStmt,
    requested_specifier: str,
) -> ParsedModule | None

Try the host resolver for speculative import edges such as child- module fallbacks while keeping expected missing-module probes silent but still surfacing unexpected resolver failures. parameters: requesting_module_key: type: ModuleKey import_node: type: astx.ImportStmt | astx.ImportFromStmt requested_specifier: type: str returns: type: ParsedModule | None

Source code in packages/irx/src/irx/analysis/session.py
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
def probe_import_specifier(
    self,
    requesting_module_key: ModuleKey,
    import_node: astx.ImportStmt | astx.ImportFromStmt,
    requested_specifier: str,
) -> ParsedModule | None:
    """
    title: Probe one import request without emitting diagnostics.
    summary: >-
      Try the host resolver for speculative import edges such as child-
      module fallbacks while keeping expected missing-module probes silent
      but still surfacing unexpected resolver failures.
    parameters:
      requesting_module_key:
        type: ModuleKey
      import_node:
        type: astx.ImportStmt | astx.ImportFromStmt
      requested_specifier:
        type: str
    returns:
      type: ParsedModule | None
    """
    cache_key = (requesting_module_key, requested_specifier)
    if cache_key in self._probe_cache:
        return self._probe_cache[cache_key]

    try:
        resolved = self.resolver(
            requesting_module_key,
            import_node,
            requested_specifier,
        )
    except LookupError:
        self._probe_cache[cache_key] = None
        return None

    self.register_module(resolved)
    self._probe_cache[cache_key] = resolved
    return resolved

register_module

register_module(
    parsed_module: ParsedModule,
) -> ParsedModule

Cache a parsed module once and initialize its graph and visible binding slots. parameters: parsed_module: type: ParsedModule returns: type: ParsedModule

Source code in packages/irx/src/irx/analysis/session.py
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
def register_module(self, parsed_module: ParsedModule) -> ParsedModule:
    """
    title: Register one parsed module in the session cache.
    summary: >-
      Cache a parsed module once and initialize its graph and visible
      binding slots.
    parameters:
      parsed_module:
        type: ParsedModule
    returns:
      type: ParsedModule
    """
    existing = self.modules.get(parsed_module.key)
    if existing is not None:
        return existing
    self.modules[parsed_module.key] = parsed_module
    self.graph.setdefault(parsed_module.key, set())
    self.visible_bindings.setdefault(parsed_module.key, {})
    return parsed_module

resolve_import_from_name

resolve_import_from_name(
    requesting_module_key: ModuleKey,
    import_node: ImportFromStmt,
    parent_module_key: ModuleKey,
    imported_name: str,
) -> tuple[SemanticBinding | None, ParsedModule | None]

-

Resolve one import-from name to a direct binding or child module.

Apply symbol-first, child-module-second import-from semantics using the parent module's visible bindings before attempting module namespace fallback. parameters: requesting_module_key: type: ModuleKey import_node: type: astx.ImportFromStmt parent_module_key: type: ModuleKey imported_name: type: str returns: type: tuple[SemanticBinding | None, ParsedModule | None]

Source code in packages/irx/src/irx/analysis/session.py
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
def resolve_import_from_name(
    self,
    requesting_module_key: ModuleKey,
    import_node: astx.ImportFromStmt,
    parent_module_key: ModuleKey,
    imported_name: str,
) -> tuple[SemanticBinding | None, ParsedModule | None]:
    """
    title: >-
      Resolve one import-from name to a direct binding or child module.
    summary: >-
      Apply symbol-first, child-module-second import-from semantics using
      the parent module's visible bindings before attempting module
      namespace fallback.
    parameters:
      requesting_module_key:
        type: ModuleKey
      import_node:
        type: astx.ImportFromStmt
      parent_module_key:
        type: ModuleKey
      imported_name:
        type: str
    returns:
      type: tuple[SemanticBinding | None, ParsedModule | None]
    """
    target_binding = self.visible_bindings.get(parent_module_key, {}).get(
        imported_name
    )
    if (
        target_binding is not None
        and target_binding.kind in _IMPORTABLE_BINDING_KINDS
    ):
        return target_binding, None

    requested_specifier = f"{parent_module_key}.{imported_name}"
    resolved_child = self.probe_import_specifier(
        requesting_module_key,
        import_node,
        requested_specifier,
    )
    return None, resolved_child

resolve_import_specifier

resolve_import_specifier(
    requesting_module_key: ModuleKey,
    import_node: ImportStmt | ImportFromStmt,
    requested_specifier: str,
) -> ParsedModule | None

Call the host resolver once per import request, memoizing both successes and failures. parameters: requesting_module_key: type: ModuleKey import_node: type: astx.ImportStmt | astx.ImportFromStmt requested_specifier: type: str returns: type: ParsedModule | None

Source code in packages/irx/src/irx/analysis/session.py
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
def resolve_import_specifier(
    self,
    requesting_module_key: ModuleKey,
    import_node: astx.ImportStmt | astx.ImportFromStmt,
    requested_specifier: str,
) -> ParsedModule | None:
    """
    title: Resolve one import request through the host resolver.
    summary: >-
      Call the host resolver once per import request, memoizing both
      successes and failures.
    parameters:
      requesting_module_key:
        type: ModuleKey
      import_node:
        type: astx.ImportStmt | astx.ImportFromStmt
      requested_specifier:
        type: str
    returns:
      type: ParsedModule | None
    """
    cache_key = (requesting_module_key, requested_specifier)
    if cache_key in self._resolution_cache:
        return self._resolution_cache[cache_key]
    if (
        cache_key in self._probe_cache
        and self._probe_cache[cache_key] is not None
    ):
        resolved = self._probe_cache[cache_key]
        self._resolution_cache[cache_key] = resolved
        return resolved

    try:
        resolved = self.resolver(
            requesting_module_key,
            import_node,
            requested_specifier,
        )
    except Exception as exc:
        self.diagnostics.add(
            f"Unable to resolve module '{requested_specifier}': {exc}",
            node=import_node,
            module_key=requesting_module_key,
        )
        self._resolution_cache[cache_key] = None
        return None

    self.register_module(resolved)
    self._probe_cache[cache_key] = resolved
    self._resolution_cache[cache_key] = resolved
    return resolved

Diagnostic dataclass

Diagnostic(
    message: str,
    node: AST | None = None,
    code: str | None = None,
    severity: str = "error",
    module_key: str | None = None,
    phase: str = "semantic",
    source: SourceLocation | None = None,
    notes: tuple[str, ...] = (),
    hint: str | None = None,
    cause: Exception | None = None,
    related: tuple[DiagnosticRelatedInformation, ...] = (),
)

Methods:

format

format(
    *, code_formatter: DiagnosticCodeFormatter | None = None
) -> str
Source code in packages/irx/src/irx/diagnostics.py
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
def format(
    self,
    *,
    code_formatter: DiagnosticCodeFormatter | None = None,
) -> str:
    """
    title: Format the diagnostic for human display.
    parameters:
      code_formatter:
        type: DiagnosticCodeFormatter | None
    returns:
      type: str
    """
    prefix = format_source_location(
        self.resolved_module_key(),
        self.resolved_source(),
    )
    prefix_text = f"{prefix}: " if prefix else ""
    rendered_code = self.rendered_code(code_formatter=code_formatter)
    label = self.severity
    if rendered_code is not None:
        label = f"{label}[{rendered_code}]"
    if self.phase and self.phase != "semantic":
        label = f"{label} ({self.phase})"

    lines = [f"{prefix_text}{label}: {self.message}"]
    for note in self.notes:
        lines.append(f"  note: {note}")
    if self.hint is not None:
        lines.append(f"  hint: {self.hint}")
    if self.cause is not None:
        cause_message = (
            str(self.cause).strip() or self.cause.__class__.__name__
        )
        lines.append(
            f"  cause: {self.cause.__class__.__name__}: {cause_message}"
        )
    for related in self.related:
        related_prefix = format_source_location(
            related.resolved_module_key(),
            related.resolved_source(),
        )
        related_text = (
            f"{related_prefix}: {related.message}"
            if related_prefix
            else related.message
        )
        lines.append(f"  related: {related_text}")
    return "\n".join(lines)

rendered_code

rendered_code(
    *, code_formatter: DiagnosticCodeFormatter | None = None
) -> str | None
Source code in packages/irx/src/irx/diagnostics.py
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
def rendered_code(
    self,
    *,
    code_formatter: DiagnosticCodeFormatter | None = None,
) -> str | None:
    """
    title: Return the final rendered diagnostic code.
    parameters:
      code_formatter:
        type: DiagnosticCodeFormatter | None
    returns:
      type: str | None
    """
    return format_diagnostic_code(
        self.code,
        code_formatter=code_formatter,
    )

resolved_module_key

resolved_module_key() -> str | None
Source code in packages/irx/src/irx/diagnostics.py
418
419
420
421
422
423
424
def resolved_module_key(self) -> str | None:
    """
    title: Return the diagnostic's best-effort module attribution.
    returns:
      type: str | None
    """
    return self.module_key or get_node_module_key(self.node)

resolved_source

resolved_source() -> SourceLocation | None
Source code in packages/irx/src/irx/diagnostics.py
410
411
412
413
414
415
416
def resolved_source(self) -> SourceLocation | None:
    """
    title: Return the diagnostic's best-effort source location.
    returns:
      type: SourceLocation | None
    """
    return self.source or get_node_source_location(self.node)

DiagnosticBag

DiagnosticBag()

Methods:

Source code in packages/irx/src/irx/diagnostics.py
510
511
512
513
514
515
def __init__(self) -> None:
    """
    title: Initialize DiagnosticBag.
    """
    self.diagnostics = []
    self.default_module_key = None

add

add(
    message: str,
    *,
    node: AST | None = None,
    code: str | None = None,
    severity: str = "error",
    module_key: str | None = None,
    phase: str = "semantic",
    source: SourceLocation | None = None,
    notes: Iterable[str] = (),
    hint: str | None = None,
    cause: Exception | None = None,
    related: Iterable[DiagnosticRelatedInformation] = (),
) -> None
Source code in packages/irx/src/irx/diagnostics.py
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
def add(
    self,
    message: str,
    *,
    node: astx.AST | None = None,
    code: str | None = None,
    severity: str = "error",
    module_key: str | None = None,
    phase: str = "semantic",
    source: SourceLocation | None = None,
    notes: Iterable[str] = (),
    hint: str | None = None,
    cause: Exception | None = None,
    related: Iterable[DiagnosticRelatedInformation] = (),
) -> None:
    """
    title: Add one diagnostic to the bag.
    parameters:
      message:
        type: str
      node:
        type: astx.AST | None
      code:
        type: str | None
      severity:
        type: str
      module_key:
        type: str | None
      phase:
        type: str
      source:
        type: SourceLocation | None
      notes:
        type: Iterable[str]
      hint:
        type: str | None
      cause:
        type: Exception | None
      related:
        type: Iterable[DiagnosticRelatedInformation]
    """
    self.diagnostics.append(
        Diagnostic(
            message=message,
            node=node,
            code=code,
            severity=severity,
            module_key=module_key or self.default_module_key,
            phase=phase,
            source=source,
            notes=tuple(notes),
            hint=hint,
            cause=cause,
            related=tuple(related),
        )
    )

extend

extend(diagnostics: Iterable[Diagnostic]) -> None
Source code in packages/irx/src/irx/diagnostics.py
574
575
576
577
578
579
580
581
def extend(self, diagnostics: Iterable[Diagnostic]) -> None:
    """
    title: Extend the bag with additional diagnostics.
    parameters:
      diagnostics:
        type: Iterable[Diagnostic]
    """
    self.diagnostics.extend(diagnostics)

format

format(
    *, code_formatter: DiagnosticCodeFormatter | None = None
) -> str
Source code in packages/irx/src/irx/diagnostics.py
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
def format(
    self,
    *,
    code_formatter: DiagnosticCodeFormatter | None = None,
) -> str:
    """
    title: Format the whole bag.
    parameters:
      code_formatter:
        type: DiagnosticCodeFormatter | None
    returns:
      type: str
    """
    return "\n".join(
        diagnostic.format(code_formatter=code_formatter)
        for diagnostic in self.diagnostics
    )

has_errors

has_errors() -> bool
Source code in packages/irx/src/irx/diagnostics.py
583
584
585
586
587
588
589
def has_errors(self) -> bool:
    """
    title: Return True when the bag contains diagnostics.
    returns:
      type: bool
    """
    return bool(self.diagnostics)

raise_if_errors

raise_if_errors() -> None
Source code in packages/irx/src/irx/diagnostics.py
609
610
611
612
613
614
def raise_if_errors(self) -> None:
    """
    title: Raise SemanticError when diagnostics exist.
    """
    if self.has_errors():
        raise SemanticError(self)

FFIAdmissibility

Bases: str, Enum

Distinguish regular IRx callables from callables that satisfy the public FFI contract.

FFICallableInfo dataclass

FFICallableInfo(
    admissibility: FFIAdmissibility,
    parameters: tuple[FFITypeInfo, ...],
    return_type: FFITypeInfo,
    required_runtime_features: tuple[str, ...] = (),
    link_strategy: FFILinkStrategy = SYSTEM_LINKER,
)

Record the validated FFI classification, type categories, symbol resolution strategy, and runtime-feature dependencies for one extern callable. attributes: admissibility: type: FFIAdmissibility parameters: type: tuple[FFITypeInfo, Ellipsis] return_type: type: FFITypeInfo required_runtime_features: type: tuple[str, Ellipsis] link_strategy: type: FFILinkStrategy

FFILinkStrategy

Bases: str, Enum

Describe whether an extern symbol relies only on the system linker or on one or more explicit runtime features.

FFITypeClass

Bases: str, Enum

Classify the narrow set of public ABI-safe value categories supported by IRx's current FFI contract.

FFITypeInfo dataclass

FFITypeInfo(
    classification: FFITypeClass,
    display_name: str,
    metadata: dict[str, Any] = dict(),
)

Describe how one semantically validated public FFI type participates in the stable ABI contract. attributes: classification: type: FFITypeClass display_name: type: str metadata: type: dict[str, Any]

ImportResolver

Bases: Protocol

Describe the host-owned callback IRx uses to turn import specifiers into already-parsed modules.

IterationKind

Bases: str, Enum

Classify the semantic adapter that turns one iterable expression into a backend iteration plan.

IterationOrder

Bases: str, Enum

Describe the user-visible order guarantee, if any, exposed by one iterable adapter.

MethodDispatchKind

Bases: str, Enum

Distinguish direct method calls from dispatch-table-driven instance calls.

ParsedModule dataclass

ParsedModule(
    key: ModuleKey,
    ast: Module,
    display_name: str | None = None,
    origin: str | None = None,
)

Bundle a host-owned module key with the parsed AST and optional human- facing origin metadata. attributes: key: type: ModuleKey ast: type: astx.Module display_name: type: str | None origin: type: str | None

PhaseErrorBoundary dataclass

PhaseErrorBoundary(
    phase: str,
    raises: str,
    surfaces: tuple[str, ...],
    summary: str,
)

Describe which category of failure belongs to which pipeline phase and how callers should interpret it. attributes: phase: type: str raises: type: str surfaces: type: tuple[str, Ellipsis] summary: type: str

ResolvedAssignment dataclass

ResolvedAssignment(target: SemanticSymbol)

Point from an assignment-like node back to the resolved target symbol it mutates. attributes: target: type: SemanticSymbol

ResolvedBaseClassFieldAccess dataclass

ResolvedBaseClassFieldAccess(
    receiver_class: SemanticClass,
    base_class: SemanticClass,
    member: SemanticClassMember,
    field: SemanticClassLayoutField,
)

Point from a base-qualified instance attribute read to the selected base view, concrete receiver class, and stable flattened layout slot. attributes: receiver_class: type: SemanticClass base_class: type: SemanticClass member: type: SemanticClassMember field: type: SemanticClassLayoutField

ResolvedClassConstruction dataclass

ResolvedClassConstruction(
    class_: SemanticClass,
    initialization: SemanticClassInitialization,
)

Capture the analyzed class identity and ordered initialization plan for one default class construction expression. attributes: class_: type: SemanticClass initialization: type: SemanticClassInitialization

ResolvedClassFieldAccess dataclass

ResolvedClassFieldAccess(
    class_: SemanticClass,
    member: SemanticClassMember,
    field: SemanticClassLayoutField,
)

Point from a class-attribute access node to the owning class member and stable flattened layout slot. attributes: class_: type: SemanticClass member: type: SemanticClassMember field: type: SemanticClassLayoutField

ResolvedCollectionMethod dataclass

ResolvedCollectionMethod(
    receiver_node: AST,
    receiver_type: DataType,
    method: CollectionMethodKind,
    return_type: DataType,
    argument_types: tuple[DataType, ...] = (),
    mutates: bool = False,
    extras: dict[str, Any] = dict(),
)

Attach the semantic collection operation that lowering should consume without re-resolving receiver kind or result type. attributes: receiver_node: type: astx.AST receiver_type: type: astx.DataType method: type: CollectionMethodKind return_type: type: astx.DataType argument_types: type: tuple[astx.DataType, Ellipsis] mutates: type: bool extras: type: dict[str, Any]

ResolvedContextManager dataclass

ResolvedContextManager(
    class_: SemanticClass,
    manager_type: DataType,
    enter: ResolvedMethodCall,
    exit: ResolvedMethodCall,
    target_symbol: SemanticSymbol | None = None,
)

Capture the manager class, resolved __enter__/__exit__ methods, and optional target binding for one with statement. attributes: class_: type: SemanticClass manager_type: type: astx.DataType enter: type: ResolvedMethodCall exit: type: ResolvedMethodCall target_symbol: type: SemanticSymbol | None

ResolvedImportBinding dataclass

ResolvedImportBinding(
    local_name: str,
    requested_name: str,
    source_module_key: ModuleKey,
    binding: SemanticBinding,
)

Record how one imported local name maps back to its source-module declaration. attributes: local_name: type: str requested_name: type: str source_module_key: type: ModuleKey binding: type: SemanticBinding

ResolvedIteration dataclass

ResolvedIteration(
    iterable_node: AST,
    iterable_type: DataType,
    element_type: DataType,
    kind: IterationKind,
    is_reiterable: bool = True,
    order: IterationOrder = UNSPECIFIED,
    target_symbol: SemanticSymbol | None = None,
    extras: dict[str, Any] = dict(),
)

Attach the semantic iteration plan that a for-in loop or comprehension should consume during backend lowering. attributes: iterable_node: type: astx.AST iterable_type: type: astx.DataType element_type: type: astx.DataType kind: type: IterationKind is_reiterable: type: bool order: type: IterationOrder target_symbol: type: SemanticSymbol | None extras: type: dict[str, Any]

ResolvedMethodCall dataclass

ResolvedMethodCall(
    class_: SemanticClass,
    member: SemanticClassMember,
    function: SemanticFunction,
    overload_key: str,
    dispatch_kind: MethodDispatchKind,
    call: CallResolution,
    candidates: tuple[SemanticClassMember, ...] = (),
    receiver_type: DataType | None = None,
    receiver_class: SemanticClass | None = None,
    slot_index: int | None = None,
)

Capture the resolved class member, lowered implementation, dispatch mode, and validated argument conversions for one method call site. attributes: class_: type: SemanticClass member: type: SemanticClassMember function: type: SemanticFunction overload_key: type: str dispatch_kind: type: MethodDispatchKind call: type: CallResolution candidates: type: tuple[SemanticClassMember, Ellipsis] receiver_type: type: astx.DataType | None receiver_class: type: SemanticClass | None slot_index: type: int | None

ResolvedOperator dataclass

ResolvedOperator(
    op_code: str,
    result_type: DataType | None = None,
    lhs_type: DataType | None = None,
    rhs_type: DataType | None = None,
    flags: SemanticFlags = SemanticFlags(),
)

Capture the normalized operator opcode, operand types, result type, and semantic flags for one expression. attributes: op_code: type: str result_type: type: astx.DataType | None lhs_type: type: astx.DataType | None rhs_type: type: astx.DataType | None flags: type: SemanticFlags

ResolvedStaticClassFieldAccess dataclass

ResolvedStaticClassFieldAccess(
    class_: SemanticClass,
    member: SemanticClassMember,
    storage: SemanticClassStaticStorage,
)

Point from a class-qualified static attribute read to the selected class member and stable emitted storage metadata. attributes: class_: type: SemanticClass member: type: SemanticClassMember storage: type: SemanticClassStaticStorage

SemanticAnalyzer

SemanticAnalyzer(
    *,
    context: SemanticContext | None = None,
    session: CompilationSession | None = None,
)

Bases: ImportVisitorMixin, TemplateVisitorMixin, DeclarationVisitorMixin, ExpressionVisitorMixin, ControlFlowVisitorMixin, SemanticAnalyzerCore

Walk AST nodes, attach semantic sidecars, and delegate reusable policy to the extracted factories, registries, and binding tables.

Methods:

Source code in packages/irx/src/irx/analysis/handlers/base.py
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
def __init__(
    self,
    *,
    context: SemanticContext | None = None,
    session: CompilationSession | None = None,
) -> None:
    """
    title: Initialize SemanticAnalyzerCore.
    parameters:
      context:
        type: SemanticContext | None
      session:
        type: CompilationSession | None
    """
    self.session = session
    self.context = context or SemanticContext()
    if session is not None:
        self.context.diagnostics = session.diagnostics
    self.factory = SemanticEntityFactory(self.context)
    self.registry = SemanticRegistry(self.context, self.factory)
    self.bindings = VisibleBindings(
        context=self.context,
        factory=self.factory,
        bindings=(
            session.visible_bindings if session is not None else None
        ),
    )

analyze

analyze(node: AST) -> AST
Source code in packages/irx/src/irx/analysis/handlers/base.py
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
def analyze(self, node: astx.AST) -> astx.AST:
    """
    title: Analyze one AST root.
    parameters:
      node:
        type: astx.AST
    returns:
      type: astx.AST
    """
    if isinstance(node, astx.Module):
        parsed_module = ParsedModule(node.name, node)
        self.analyze_parsed_module(parsed_module, predeclared=False)
    else:
        with self.context.scope("module"):
            self.visit(node)
    self.context.diagnostics.raise_if_errors()
    return node

analyze_parsed_module

analyze_parsed_module(
    parsed_module: ParsedModule, *, predeclared: bool
) -> Module
Source code in packages/irx/src/irx/analysis/handlers/base.py
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
def analyze_parsed_module(
    self,
    parsed_module: ParsedModule,
    *,
    predeclared: bool,
) -> astx.Module:
    """
    title: Analyze one parsed module.
    parameters:
      parsed_module:
        type: ParsedModule
      predeclared:
        type: bool
    returns:
      type: astx.Module
    """
    if not predeclared:
        reset_templates = getattr(
            self,
            "_reset_template_analysis_state",
            None,
        )
        if callable(reset_templates):
            reset_templates(parsed_module.ast)
    with self.context.in_module(parsed_module.key):
        self._visit_module(parsed_module.ast, predeclared=predeclared)
    return parsed_module.ast

visit

visit(node: ImportFromExpr) -> None
Source code in packages/irx/src/irx/analysis/handlers/imports.py
180
181
182
183
184
185
186
187
188
189
190
191
192
@SemanticAnalyzerCore.visit.dispatch
def visit(self, node: astx.ImportFromExpr) -> None:
    """
    title: Visit ImportFromExpr nodes.
    parameters:
      node:
        type: astx.ImportFromExpr
    """
    self.context.diagnostics.add(
        "Import expressions are not supported in this MVP.",
        node=node,
    )
    self._set_type(node, None)

SemanticBinding dataclass

SemanticBinding(
    kind: str,
    module_key: ModuleKey,
    qualified_name: str,
    function: SemanticFunction | None = None,
    struct: SemanticStruct | None = None,
    class_: SemanticClass | None = None,
    module: SemanticModule | None = None,
)

Normalize imported and local top-level names into one binding shape for module-visible lookup. attributes: kind: type: str module_key: type: ModuleKey qualified_name: type: str function: type: SemanticFunction | None struct: type: SemanticStruct | None class_: type: SemanticClass | None module: type: SemanticModule | None

SemanticClass dataclass

SemanticClass(
    symbol_id: str,
    name: str,
    module_key: ModuleKey,
    qualified_name: str,
    declaration: ClassDefStmt,
    bases: tuple["SemanticClass", ...] = (),
    declared_members: tuple[SemanticClassMember, ...] = (),
    declared_member_table: dict[
        str, SemanticClassMember
    ] = dict(),
    declared_method_groups: dict[
        str, tuple[SemanticClassMember, ...]
    ] = dict(),
    member_table: dict[str, SemanticClassMember] = dict(),
    method_groups: dict[
        str, tuple[SemanticClassMember, ...]
    ] = dict(),
    member_resolution: dict[
        str, SemanticClassMemberResolution
    ] = dict(),
    method_resolution: dict[
        str, tuple[SemanticClassMemberResolution, ...]
    ] = dict(),
    instance_attributes: tuple[
        SemanticClassMember, ...
    ] = (),
    static_attributes: tuple[SemanticClassMember, ...] = (),
    instance_methods: tuple[SemanticClassMember, ...] = (),
    static_methods: tuple[SemanticClassMember, ...] = (),
    abstract_methods: tuple[SemanticClassMember, ...] = (),
    inheritance_graph: tuple[str, ...] = (),
    shared_ancestors: tuple["SemanticClass", ...] = (),
    layout: SemanticClassLayout | None = None,
    initialization: SemanticClassInitialization
    | None = None,
    mro: tuple["SemanticClass", ...] = (),
    is_structurally_resolved: bool = False,
    is_resolved: bool = False,
    is_abstract: bool = False,
)

Describe one top-level class declaration together with normalized bases, member tables, and deterministic inheritance metadata. attributes: symbol_id: type: str name: type: str module_key: type: ModuleKey qualified_name: type: str declaration: type: astx.ClassDefStmt bases: type: tuple[SemanticClass, Ellipsis] declared_members: type: tuple[SemanticClassMember, Ellipsis] declared_member_table: type: dict[str, SemanticClassMember] declared_method_groups: type: dict[str, tuple[SemanticClassMember, Ellipsis]] member_table: type: dict[str, SemanticClassMember] method_groups: type: dict[str, tuple[SemanticClassMember, Ellipsis]] member_resolution: type: dict[str, SemanticClassMemberResolution] method_resolution: type: dict[str, tuple[SemanticClassMemberResolution, Ellipsis]] instance_attributes: type: tuple[SemanticClassMember, Ellipsis] static_attributes: type: tuple[SemanticClassMember, Ellipsis] instance_methods: type: tuple[SemanticClassMember, Ellipsis] static_methods: type: tuple[SemanticClassMember, Ellipsis] abstract_methods: type: tuple[SemanticClassMember, Ellipsis] inheritance_graph: type: tuple[str, Ellipsis] shared_ancestors: type: tuple[SemanticClass, Ellipsis] layout: type: SemanticClassLayout | None initialization: type: SemanticClassInitialization | None mro: type: tuple[SemanticClass, Ellipsis] is_structurally_resolved: type: bool is_resolved: type: bool is_abstract: type: bool

SemanticClassFieldInitializer dataclass

SemanticClassFieldInitializer(
    field: SemanticClassLayoutField,
    source_kind: ClassInitializationSourceKind,
    value: AST | None,
    owner_name: str,
    owner_qualified_name: str,
)

Record the ordered value source for one instance field during default class construction. attributes: field: type: SemanticClassLayoutField source_kind: type: ClassInitializationSourceKind value: type: astx.AST | None owner_name: type: str owner_qualified_name: type: str

SemanticClassHeaderField dataclass

SemanticClassHeaderField(
    name: str,
    kind: ClassHeaderFieldKind,
    storage_index: int,
)

Describe one hidden header entry that occupies a stable index in every class object representation. attributes: name: type: str kind: type: ClassHeaderFieldKind storage_index: type: int

SemanticClassInitialization dataclass

SemanticClassInitialization(
    instance_initializers: tuple[
        SemanticClassFieldInitializer, ...
    ] = (),
    static_initializers: tuple[
        SemanticClassStaticInitializer, ...
    ] = (),
)

Normalize the ordered instance-field and static-field initialization plan that semantic analysis resolves for one class. attributes: instance_initializers: type: tuple[SemanticClassFieldInitializer, Ellipsis] static_initializers: type: tuple[SemanticClassStaticInitializer, Ellipsis]

SemanticClassLayout dataclass

SemanticClassLayout(
    llvm_name: str,
    object_representation: ClassObjectRepresentationKind,
    descriptor_global_name: str,
    dispatch_global_name: str,
    header_fields: tuple[
        SemanticClassHeaderField, ...
    ] = (),
    instance_fields: tuple[
        SemanticClassLayoutField, ...
    ] = (),
    field_slots: dict[
        str, SemanticClassLayoutField
    ] = dict(),
    visible_field_slots: dict[
        str, SemanticClassLayoutField
    ] = dict(),
    dispatch_entries: tuple[
        SemanticClassMethodDispatch, ...
    ] = (),
    dispatch_slots: dict[
        int, SemanticClassMethodDispatch
    ] = dict(),
    visible_method_slots: dict[
        str, SemanticClassMethodDispatch
    ] = dict(),
    dispatch_table_size: int = 0,
    static_fields: tuple[
        SemanticClassStaticStorage, ...
    ] = (),
    static_storage: dict[
        str, SemanticClassStaticStorage
    ] = dict(),
    visible_static_storage: dict[
        str, SemanticClassStaticStorage
    ] = dict(),
)

Normalize the low-level object representation, hidden header slots, flattened instance-field storage, and static-global storage names for one class. attributes: llvm_name: type: str object_representation: type: ClassObjectRepresentationKind descriptor_global_name: type: str dispatch_global_name: type: str header_fields: type: tuple[SemanticClassHeaderField, Ellipsis] instance_fields: type: tuple[SemanticClassLayoutField, Ellipsis] field_slots: type: dict[str, SemanticClassLayoutField] visible_field_slots: type: dict[str, SemanticClassLayoutField] dispatch_entries: type: tuple[SemanticClassMethodDispatch, Ellipsis] dispatch_slots: type: dict[int, SemanticClassMethodDispatch] visible_method_slots: type: dict[str, SemanticClassMethodDispatch] dispatch_table_size: type: int static_fields: type: tuple[SemanticClassStaticStorage, Ellipsis] static_storage: type: dict[str, SemanticClassStaticStorage] visible_static_storage: type: dict[str, SemanticClassStaticStorage]

SemanticClassLayoutField dataclass

SemanticClassLayoutField(
    member: SemanticClassMember,
    logical_index: int,
    storage_index: int,
    owner_name: str,
    owner_qualified_name: str,
)

Record the stable storage position for one declared instance attribute in the flattened class-object layout. attributes: member: type: SemanticClassMember logical_index: type: int storage_index: type: int owner_name: type: str owner_qualified_name: type: str

SemanticClassMember dataclass

SemanticClassMember(
    symbol_id: str,
    name: str,
    qualified_name: str,
    owner_name: str,
    owner_qualified_name: str,
    kind: ClassMemberKind,
    visibility: VisibilityKind,
    is_static: bool,
    is_abstract: bool,
    is_constant: bool,
    is_mutable: bool,
    declaration: AST,
    type_: DataType | None = None,
    signature: FunctionSignature | None = None,
    signature_key: str | None = None,
    overrides: str | None = None,
    dispatch_slot: int | None = None,
    lowered_function: "SemanticFunction" | None = None,
)

Normalize one declared class member so later phases can reason about visibility, storage, mutability, and overrides without re-reading raw AST modifier fields. attributes: symbol_id: type: str name: type: str qualified_name: type: str owner_name: type: str owner_qualified_name: type: str kind: type: ClassMemberKind visibility: type: astx.VisibilityKind is_static: type: bool is_abstract: type: bool is_constant: type: bool is_mutable: type: bool declaration: type: astx.AST type_: type: astx.DataType | None signature: type: FunctionSignature | None signature_key: type: str | None overrides: type: str | None dispatch_slot: type: int | None lowered_function: type: SemanticFunction | None

SemanticClassMemberResolution dataclass

SemanticClassMemberResolution(
    name: str,
    kind: ClassMemberResolutionKind,
    selected: SemanticClassMember,
    candidates: tuple[SemanticClassMember, ...] = (),
    signature_key: str | None = None,
)

Record the ordered candidate set that one class member name considered and the member that won after deterministic inheritance resolution. attributes: name: type: str kind: type: ClassMemberResolutionKind selected: type: SemanticClassMember candidates: type: tuple[SemanticClassMember, Ellipsis] signature_key: type: str | None

SemanticClassMethodDispatch dataclass

SemanticClassMethodDispatch(
    member: SemanticClassMember,
    function: "SemanticFunction",
    slot_index: int,
    owner_name: str,
    owner_qualified_name: str,
)

Record the stable dispatch slot and lowered function implementation for one visible instance method. attributes: member: type: SemanticClassMember function: type: SemanticFunction slot_index: type: int owner_name: type: str owner_qualified_name: type: str

SemanticClassStaticInitializer dataclass

SemanticClassStaticInitializer(
    storage: SemanticClassStaticStorage,
    source_kind: ClassInitializationSourceKind,
    value: AST | None,
    owner_name: str,
    owner_qualified_name: str,
)

Record the deterministic module-global initializer source for one static class attribute. attributes: storage: type: SemanticClassStaticStorage source_kind: type: ClassInitializationSourceKind value: type: astx.AST | None owner_name: type: str owner_qualified_name: type: str

SemanticClassStaticStorage dataclass

SemanticClassStaticStorage(
    member: SemanticClassMember,
    global_name: str,
    owner_name: str,
    owner_qualified_name: str,
)

Describe the module-global storage backing one declared static class attribute. attributes: member: type: SemanticClassMember global_name: type: str owner_name: type: str owner_qualified_name: type: str

SemanticContract dataclass

SemanticContract(
    stable_phases: tuple[SemanticPhase, ...],
    required_node_semantic_fields: tuple[str, ...],
    required_session_fields: tuple[str, ...],
    allowed_host_entrypoints: tuple[str, ...],
    allowed_host_inputs: tuple[str, ...],
    phase_error_boundaries: tuple[PhaseErrorBoundary, ...],
)

Collect the semantic phases, metadata requirements, host input constraints, and error boundaries that analysis guarantees to lowering and host compilers. attributes: stable_phases: type: tuple[SemanticPhase, Ellipsis] required_node_semantic_fields: type: tuple[str, Ellipsis] required_session_fields: type: tuple[str, Ellipsis] allowed_host_entrypoints: type: tuple[str, Ellipsis] allowed_host_inputs: type: tuple[str, Ellipsis] phase_error_boundaries: type: tuple[PhaseErrorBoundary, Ellipsis]

SemanticError

SemanticError(
    diagnostics: DiagnosticBag,
    *,
    code_formatter: DiagnosticCodeFormatter | None = None,
)

Bases: Exception

Methods:

Source code in packages/irx/src/irx/diagnostics.py
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
def __init__(
    self,
    diagnostics: DiagnosticBag,
    *,
    code_formatter: DiagnosticCodeFormatter | None = None,
) -> None:
    """
    title: Initialize SemanticError.
    parameters:
      diagnostics:
        type: DiagnosticBag
      code_formatter:
        type: DiagnosticCodeFormatter | None
    """
    self.diagnostics = diagnostics
    self.code_formatter = code_formatter or get_diagnostic_code_formatter()
    super().__init__(
        diagnostics.format(code_formatter=self.code_formatter)
    )

format

format() -> str
Source code in packages/irx/src/irx/diagnostics.py
746
747
748
749
750
751
752
def format(self) -> str:
    """
    title: Return the formatted diagnostic bag.
    returns:
      type: str
    """
    return self.diagnostics.format(code_formatter=self.code_formatter)

SemanticFlags dataclass

SemanticFlags(
    unsigned: bool = False,
    fast_math: bool = False,
    fma: bool = False,
    fma_rhs: AST | None = None,
)

Store normalized semantic modifiers such as unsigned and fast-math intent. attributes: unsigned: type: bool fast_math: type: bool fma: type: bool fma_rhs: type: astx.AST | None

SemanticFunction dataclass

SemanticFunction(
    symbol_id: str,
    name: str,
    return_type: DataType,
    args: tuple[SemanticSymbol, ...],
    signature: FunctionSignature,
    prototype: FunctionPrototype,
    definition: FunctionDef | None = None,
    module_key: ModuleKey = (lambda: "<unknown>")(),
    qualified_name: str = "",
    template_params: tuple[TemplateParam, ...] = (),
    template_bindings: tuple[
        TemplateArgumentBinding, ...
    ] = (),
    template_definition: "SemanticFunction" | None = None,
    specialization_key: TemplateSpecializationKey
    | None = None,
    specializations: dict[
        TemplateSpecializationKey, "SemanticFunction"
    ] = dict(),
)

Describe one top-level function declaration or definition together with its semantic identity, canonical signature, and argument symbols. attributes: symbol_id: type: str name: type: str return_type: type: astx.DataType args: type: tuple[SemanticSymbol, Ellipsis] signature: type: FunctionSignature prototype: type: astx.FunctionPrototype definition: type: astx.FunctionDef | None module_key: type: ModuleKey qualified_name: type: str template_params: type: tuple[astx.TemplateParam, Ellipsis] template_bindings: type: tuple[TemplateArgumentBinding, Ellipsis] template_definition: type: SemanticFunction | None specialization_key: type: TemplateSpecializationKey | None specializations: type: dict[TemplateSpecializationKey, SemanticFunction]

SemanticInfo dataclass

SemanticInfo(
    resolved_type: DataType | None = None,
    resolved_symbol: SemanticSymbol | None = None,
    resolved_function: SemanticFunction | None = None,
    resolved_callable: CallableResolution | None = None,
    resolved_struct: SemanticStruct | None = None,
    resolved_class: SemanticClass | None = None,
    resolved_module: SemanticModule | None = None,
    resolved_imports: tuple[
        ResolvedImportBinding, ...
    ] = (),
    resolved_call: CallResolution | None = None,
    resolved_operator: ResolvedOperator | None = None,
    resolved_assignment: ResolvedAssignment | None = None,
    resolved_field_access: ResolvedFieldAccess
    | None = None,
    resolved_module_member_access: ResolvedModuleMemberAccess
    | None = None,
    resolved_class_field_access: ResolvedClassFieldAccess
    | None = None,
    resolved_base_class_field_access: ResolvedBaseClassFieldAccess
    | None = None,
    resolved_static_class_field_access: ResolvedStaticClassFieldAccess
    | None = None,
    resolved_method_call: ResolvedMethodCall | None = None,
    resolved_context_manager: ResolvedContextManager
    | None = None,
    resolved_class_construction: ResolvedClassConstruction
    | None = None,
    resolved_return: ReturnResolution | None = None,
    resolved_generator_function: ResolvedGeneratorFunction
    | None = None,
    resolved_yield: ResolvedYield | None = None,
    resolved_iteration: ResolvedIteration | None = None,
    resolved_collection_method: ResolvedCollectionMethod
    | None = None,
    semantic_flags: SemanticFlags = SemanticFlags(),
    extras: dict[str, Any] = dict(),
)

Aggregate all semantic sidecar fields that analysis may attach to a single AST node. attributes: resolved_type: type: astx.DataType | None resolved_symbol: type: SemanticSymbol | None resolved_function: type: SemanticFunction | None resolved_callable: type: CallableResolution | None resolved_struct: type: SemanticStruct | None resolved_class: type: SemanticClass | None resolved_module: type: SemanticModule | None resolved_imports: type: tuple[ResolvedImportBinding, Ellipsis] resolved_call: type: CallResolution | None resolved_operator: type: ResolvedOperator | None resolved_assignment: type: ResolvedAssignment | None resolved_field_access: type: ResolvedFieldAccess | None resolved_module_member_access: type: ResolvedModuleMemberAccess | None resolved_class_field_access: type: ResolvedClassFieldAccess | None resolved_base_class_field_access: type: ResolvedBaseClassFieldAccess | None resolved_static_class_field_access: type: ResolvedStaticClassFieldAccess | None resolved_method_call: type: ResolvedMethodCall | None resolved_context_manager: type: ResolvedContextManager | None resolved_class_construction: type: ResolvedClassConstruction | None resolved_return: type: ReturnResolution | None resolved_generator_function: type: ResolvedGeneratorFunction | None resolved_yield: type: ResolvedYield | None resolved_iteration: type: ResolvedIteration | None resolved_collection_method: type: ResolvedCollectionMethod | None semantic_flags: type: SemanticFlags extras: type: dict[str, Any]

SemanticModule dataclass

SemanticModule(
    module_key: ModuleKey, display_name: str | None = None
)

Represent a module binding that plain imports introduce into a module namespace. attributes: module_key: type: ModuleKey display_name: type: str | None

SemanticPhase dataclass

SemanticPhase(
    name: str,
    entrypoints: tuple[str, ...],
    guarantees: tuple[str, ...],
)

Describe one externally-visible stage in the semantic pipeline and the guarantees it establishes for later lowering. attributes: name: type: str entrypoints: type: tuple[str, Ellipsis] guarantees: type: tuple[str, Ellipsis]

SemanticStruct dataclass

SemanticStruct(
    symbol_id: str,
    name: str,
    module_key: ModuleKey,
    qualified_name: str,
    declaration: StructDefStmt,
    fields: tuple["SemanticStructField", ...] = (),
    field_indices: dict[str, int] = dict(),
)

Describe one top-level struct declaration with module-aware identity. attributes: symbol_id: type: str name: type: str module_key: type: ModuleKey qualified_name: type: str declaration: type: astx.StructDefStmt fields: type: tuple[SemanticStructField, Ellipsis] field_indices: type: dict[str, int]

SemanticSymbol dataclass

SemanticSymbol(
    symbol_id: str,
    name: str,
    type_: DataType,
    is_mutable: bool,
    kind: str,
    declaration: AST | None = None,
    module_key: ModuleKey = (lambda: "<unknown>")(),
    qualified_name: str = "",
)

Describe one resolved variable-like symbol, including its stable semantic id and declared type. attributes: symbol_id: type: str name: type: str type_: type: astx.DataType is_mutable: type: bool kind: type: str declaration: type: astx.AST | None module_key: type: ModuleKey qualified_name: type: str

TemplateArgumentBinding dataclass

TemplateArgumentBinding(name: str, type_: DataType)

Record the concrete type selected for one named template parameter in a specialization. attributes: name: type: str type_: type: astx.DataType

TemplateSpecializationKey dataclass

TemplateSpecializationKey(
    qualified_name: str, arg_type_names: tuple[str, ...]
)

Identify one concrete specialization of a template function by the original semantic function name and the ordered concrete type names. attributes: qualified_name: type: str arg_type_names: type: tuple[str, Ellipsis]

analyze

analyze(node: AST) -> AST

Run the stable single-root semantic-validation path, attach node.semantic sidecars to analyzed nodes, and raise SemanticError before lowering when diagnostics exist. parameters: node: type: astx.AST returns: type: astx.AST

Source code in packages/irx/src/irx/analysis/api.py
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@public
@typechecked
def analyze(node: astx.AST) -> astx.AST:
    """
    title: Analyze one AST root and attach semantic sidecars.
    summary: >-
      Run the stable single-root semantic-validation path, attach node.semantic
      sidecars to analyzed nodes, and raise SemanticError before lowering when
      diagnostics exist.
    parameters:
      node:
        type: astx.AST
    returns:
      type: astx.AST
    """
    return SemanticAnalyzer().analyze(node)

analyze_module

analyze_module(module: Module) -> Module

Convenience wrapper around analyze(...) for module roots with the same semantic-error boundary and sidecar guarantees. parameters: module: type: astx.Module returns: type: astx.Module

Source code in packages/irx/src/irx/analysis/api.py
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
@public
@typechecked
def analyze_module(module: astx.Module) -> astx.Module:
    """
    title: Analyze an AST module.
    summary: >-
      Convenience wrapper around analyze(...) for module roots with the same
      semantic-error boundary and sidecar guarantees.
    parameters:
      module:
        type: astx.Module
    returns:
      type: astx.Module
    """
    return cast(astx.Module, analyze(module))

analyze_modules

analyze_modules(
    root: ParsedModule, resolver: ImportResolver
) -> CompilationSession

Run the stable multi-module semantic pipeline: expand the reachable module graph, predeclare top-level members, resolve top-level imports, attach semantic sidecars, and raise SemanticError before lowering when diagnostics exist. parameters: root: type: ParsedModule resolver: type: ImportResolver returns: type: CompilationSession

Source code in packages/irx/src/irx/analysis/api.py
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
@public
@typechecked
def analyze_modules(
    root: ParsedModule,
    resolver: ImportResolver,
) -> CompilationSession:
    """
    title: Analyze a reachable graph of host-provided parsed modules.
    summary: >-
      Run the stable multi-module semantic pipeline: expand the reachable
      module graph, predeclare top-level members, resolve top-level imports,
      attach semantic sidecars, and raise SemanticError before lowering when
      diagnostics exist.
    parameters:
      root:
        type: ParsedModule
      resolver:
        type: ImportResolver
    returns:
      type: CompilationSession
    """
    session = CompilationSession(root=root, resolver=resolver)
    session.expand_graph()

    analyzer = SemanticAnalyzer(session=session)

    for parsed_module in session.ordered_modules():
        analyzer._reset_template_analysis_state(parsed_module.ast)

    for parsed_module in session.ordered_modules():
        with analyzer.context.in_module(parsed_module.key):
            analyzer._predeclare_module_members(parsed_module.ast)

    for parsed_module in session.ordered_modules():
        with analyzer.context.in_module(parsed_module.key):
            with analyzer.context.scope("module"):
                for node in parsed_module.ast.nodes:
                    if isinstance(
                        node,
                        (astx.ImportStmt, astx.ImportFromStmt),
                    ):
                        analyzer.visit(node)

    for parsed_module in session.ordered_modules():
        with analyzer.context.in_module(parsed_module.key):
            analyzer._prepare_template_specialization_skeletons(
                parsed_module.ast
            )

    for parsed_module in session.ordered_modules():
        with analyzer.context.in_module(parsed_module.key):
            analyzer._analyze_prepared_template_specializations(
                parsed_module.ast
            )

    for parsed_module in session.ordered_modules():
        analyzer.analyze_parsed_module(parsed_module, predeclared=True)

    session.diagnostics.raise_if_errors()
    return session

get_semantic_contract

get_semantic_contract() -> SemanticContract

Expose the semantic contract that hosts and backend lowering may rely on before code generation begins. returns: type: SemanticContract

Source code in packages/irx/src/irx/analysis/contract.py
261
262
263
264
265
266
267
268
269
270
271
272
@public
@typechecked
def get_semantic_contract() -> SemanticContract:
    """
    title: Return the stable public semantic contract.
    summary: >-
      Expose the semantic contract that hosts and backend lowering may rely on
      before code generation begins.
    returns:
      type: SemanticContract
    """
    return _SEMANTIC_CONTRACT

resolve_iteration_capability

resolve_iteration_capability(
    iterable_node: AST, iterable_type: DataType | None
) -> ResolvedIteration | None

Return the canonical iteration sidecar for known concrete iterable types, or None when the expression is not iterable in the current IRx contract. parameters: iterable_node: type: astx.AST iterable_type: type: astx.DataType | None returns: type: ResolvedIteration | None

Source code in packages/irx/src/irx/analysis/iterables.py
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
@public
@typechecked
def resolve_iteration_capability(
    iterable_node: astx.AST,
    iterable_type: astx.DataType | None,
) -> ResolvedIteration | None:
    """
    title: Resolve one iterable semantic capability.
    summary: >-
      Return the canonical iteration sidecar for known concrete iterable types,
      or None when the expression is not iterable in the current IRx contract.
    parameters:
      iterable_node:
        type: astx.AST
      iterable_type:
        type: astx.DataType | None
    returns:
      type: ResolvedIteration | None
    """
    if iterable_type is None:
        return None

    list_type = list_element_type(iterable_type)
    if list_type is not None:
        return ResolvedIteration(
            iterable_node=iterable_node,
            iterable_type=iterable_type,
            element_type=list_type,
            kind=IterationKind.LIST,
            order=IterationOrder.INDEX,
        )

    if isinstance(iterable_type, astx.DictType) and isinstance(
        iterable_type.key_type,
        astx.DataType,
    ):
        return ResolvedIteration(
            iterable_node=iterable_node,
            iterable_type=iterable_type,
            element_type=iterable_type.key_type,
            kind=IterationKind.DICT_KEYS,
            order=IterationOrder.INSERTION,
        )

    if isinstance(iterable_type, astx.SetType) and isinstance(
        iterable_type.element_type,
        astx.DataType,
    ):
        return ResolvedIteration(
            iterable_node=iterable_node,
            iterable_type=iterable_type,
            element_type=iterable_type.element_type,
            kind=IterationKind.SET,
            order=IterationOrder.UNSPECIFIED,
        )

    if isinstance(iterable_type, astx.GeneratorType):
        return ResolvedIteration(
            iterable_node=iterable_node,
            iterable_type=iterable_type,
            element_type=iterable_type.yield_type,
            kind=IterationKind.GENERATOR,
            is_reiterable=False,
            order=IterationOrder.STABLE,
        )

    return None