# Method dispatch

## Method dispatch

The class-method resolution rule that pairs with the
[typeclasses](0013-typeclasses.md) contract; the `Show`/`Eq`/`Ord` instances
the rule dispatches against live in [prelude classes](0017-prelude-classes.md).

Dispatch is two-mode:

**Polymorphic call sites** (inside a fn body with `forall` +
constraint set): the constraint names the class via the qualified
`Constraint.class` field (canonical form: bare for same-module,
`<module>.<Class>` for cross-module; see
[memory model](0008-memory-model.md) for the canonical-form rule).
Synth's residual carries the class name directly;
constraint-discharge at fn-body-end matches against the workspace
registry by `(class, type_hash)` key.

**Monomorphic call sites**: synth consults the workspace-flat
`Env.method_to_candidate_classes: BTreeMap<MethodName,
BTreeSet<QualifiedClassName>>` index, then runs the 5-step
dispatch rule:

1. Parse the `Term::Var.name` for an optional class qualifier
   (last-dot-segment is the method name; everything before is the
   qualified class).
2. If `method_to_candidate_classes` has no entry for the method
   name, fall through to the existing Var-arm branches (free fn
   lookup, dot-qualified cross-module).
3. Qualifier present: filter candidates to the named class. Empty
   result fires `UnknownClass`. Singleton survivor proceeds.
4. Qualifier empty (bare-method form): singleton candidate proceeds
   directly; multiple candidates yield a multi-candidate residual
   for discharge-time refinement.
5. At discharge, refinement runs: concrete `type_` filters
   candidates via the workspace registry; rigid-var `type_` filters
   via the active fn's declared constraints
   (`env.active_declared_constraints`). Single survivor discharges;
   multiple survivors fire `AmbiguousMethodResolution` (concrete) or
   `MissingConstraint` (rigid-var); zero survivors fire `NoInstance`
   (concrete) or `MissingConstraint` (rigid-var).

The `method_to_candidate_classes` index is the load-bearing data
structure for this routing — its construction in `build_check_env`
inverts the per-module `class_methods` maps (themselves tuple-keyed
by `(qualified-class, method)`) to a workspace-flat
method-name-to-class-set map.

Class-fn collisions resolve at the call site, not at workspace load
time: the fn lookup precedence (locals → caller-module-fn →
imported-fn) runs ahead of the class-method branch. When both
sides have a match, the fn wins and a `class-method-shadowed-by-fn`
warning surfaces the shadow.

Ratified by: `crates/ail/tests/show_no_instance_e2e.rs`.
