# 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, `.` 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>` 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`.