11use std:: fmt:: Write ;
22use std:: sync:: Arc ;
33
4+ use building_types:: QueryResult ;
45use indexmap:: IndexSet ;
56use itertools:: Itertools ;
67use petgraph:: prelude:: DiGraphMap ;
78use petgraph:: visit:: { DfsPostOrder , Reversed } ;
89use rustc_hash:: FxHashSet ;
910use smol_str:: SmolStrBuilder ;
1011
12+ use crate :: ExternalQueries ;
13+ use crate :: algorithm:: constraint:: {
14+ ConstraintApplication , constraint_application, elaborate_superclasses,
15+ } ;
1116use crate :: algorithm:: fold:: Zonk ;
12- use crate :: algorithm:: state:: CheckState ;
17+ use crate :: algorithm:: state:: { CheckContext , CheckState } ;
1318use crate :: algorithm:: substitute:: { ShiftLevels , SubstituteUnification , UniToLevel } ;
1419use crate :: core:: { ForallBinder , RowType , Type , TypeId , debruijn} ;
1520
@@ -52,8 +57,8 @@ pub fn quantify(state: &mut CheckState, id: TypeId) -> Option<(TypeId, debruijn:
5257 Some ( ( quantified, size) )
5358}
5459
55- /// Output of constraint quantification .
56- pub struct QuantifyConstraints {
60+ /// The result of generalisation including constraints .
61+ pub struct QuantifiedWithConstraints {
5762 /// The quantified type with generalisable constraints.
5863 pub quantified : TypeId ,
5964 /// The number of quantified type variables.
@@ -73,19 +78,24 @@ pub struct QuantifyConstraints {
7378///
7479/// Generalisable constraints are added to the signature before generalisation.
7580/// Ambiguous and unsatisfied constraints are returned for error reporting.
76- pub fn quantify_with_constraints (
81+ pub fn quantify_with_constraints < Q > (
7782 state : & mut CheckState ,
83+ context : & CheckContext < Q > ,
7884 type_id : TypeId ,
7985 constraints : Vec < TypeId > ,
80- ) -> Option < QuantifyConstraints > {
86+ ) -> QueryResult < Option < QuantifiedWithConstraints > >
87+ where
88+ Q : ExternalQueries ,
89+ {
8190 if constraints. is_empty ( ) {
82- let ( quantified, size) = quantify ( state, type_id) ?;
83- return Some ( QuantifyConstraints {
84- quantified,
85- size,
86- ambiguous : vec ! [ ] ,
87- unsatisfied : vec ! [ ] ,
88- } ) ;
91+ let Some ( ( quantified, size) ) = quantify ( state, type_id) else {
92+ return Ok ( None ) ;
93+ } ;
94+
95+ let quantified_with_constraints =
96+ QuantifiedWithConstraints { quantified, size, ambiguous : vec ! [ ] , unsatisfied : vec ! [ ] } ;
97+
98+ return Ok ( Some ( quantified_with_constraints) ) ;
8999 }
90100
91101 let unsolved_graph = collect_unification ( state, type_id) ;
@@ -108,14 +118,74 @@ pub fn quantify_with_constraints(
108118 }
109119
110120 // Subtle: stable ordering for consistent output
111- let valid = valid. into_iter ( ) . sorted ( ) ;
121+ let valid = valid. into_iter ( ) . sorted ( ) . collect_vec ( ) ;
122+ let minimized = minimize_by_superclasses ( state, context, valid) ?;
112123
113- let constrained_type = valid . rfold ( type_id, |constrained, constraint| {
124+ let constrained_type = minimized . into_iter ( ) . rfold ( type_id, |constrained, constraint| {
114125 state. storage . intern ( Type :: Constrained ( constraint, constrained) )
115126 } ) ;
116127
117- let ( quantified, size) = quantify ( state, constrained_type) ?;
118- Some ( QuantifyConstraints { quantified, size, ambiguous, unsatisfied } )
128+ let Some ( ( quantified, size) ) = quantify ( state, constrained_type) else {
129+ return Ok ( None ) ;
130+ } ;
131+
132+ let quantified_with_constraints =
133+ QuantifiedWithConstraints { quantified, size, ambiguous, unsatisfied } ;
134+
135+ Ok ( Some ( quantified_with_constraints) )
136+ }
137+
138+ /// Removes constraints that are implied by other constraints via superclass relationships.
139+ ///
140+ /// For example, given constraints `[Apply f, Applicative f, Functor f]`, this function
141+ /// returns only `[Applicative f]` because `Applicative` implies both `Apply` and `Functor`.
142+ ///
143+ /// Uses GHC's algorithm (mkMinimalBySCs): O(n × superclass_depth)
144+ /// 1. Build the union of all superclass constraints
145+ /// 2. Filter out constraints that appear in the union
146+ fn minimize_by_superclasses < Q > (
147+ state : & mut CheckState ,
148+ context : & CheckContext < Q > ,
149+ constraints : Vec < TypeId > ,
150+ ) -> QueryResult < Vec < TypeId > >
151+ where
152+ Q : ExternalQueries ,
153+ {
154+ if constraints. len ( ) <= 1 {
155+ return Ok ( constraints) ;
156+ }
157+
158+ // Collect the set of all superclasses, including transitive ones.
159+ let mut superclasses = FxHashSet :: default ( ) ;
160+ for & constraint in & constraints {
161+ for application in superclass_applications ( state, context, constraint) ? {
162+ superclasses. insert ( application) ;
163+ }
164+ }
165+
166+ // Remove constraints found in the superclasses, keeping the most specific.
167+ let minimized = constraints. into_iter ( ) . filter ( |& constraint| {
168+ constraint_application ( state, constraint)
169+ . map_or ( true , |constraint| !superclasses. contains ( & constraint) )
170+ } ) ;
171+
172+ Ok ( minimized. collect_vec ( ) )
173+ }
174+
175+ fn superclass_applications < Q > (
176+ state : & mut CheckState ,
177+ context : & CheckContext < Q > ,
178+ constraint : TypeId ,
179+ ) -> QueryResult < Vec < ConstraintApplication > >
180+ where
181+ Q : ExternalQueries ,
182+ {
183+ let mut superclasses = vec ! [ ] ;
184+ elaborate_superclasses ( state, context, constraint, & mut superclasses) ?;
185+ Ok ( superclasses
186+ . into_iter ( )
187+ . filter_map ( |constraint| constraint_application ( state, constraint) )
188+ . collect ( ) )
119189}
120190
121191fn generate_type_name ( id : u32 ) -> smol_str:: SmolStr {
0 commit comments