2
2
3
3
use std:: {
4
4
borrow:: Cow ,
5
- cell:: Cell ,
5
+ cell:: { Cell , RefCell } ,
6
6
cmp,
7
7
collections:: { BTreeMap , BTreeSet } ,
8
8
fmt:: { self , Write } ,
@@ -147,7 +147,11 @@ impl<'a, E> Unifier<'a, E> {
147
147
}
148
148
}
149
149
150
- fn finish < T > ( mut self , value : T , mk_error : impl Fn ( Error ) -> E ) -> Result < T , Errors < E > > {
150
+ fn finish (
151
+ mut self ,
152
+ value : MonoType ,
153
+ mk_error : impl Fn ( Error ) -> E ,
154
+ ) -> Result < MonoType , Errors < E > > {
151
155
if !self . delayed_records . is_empty ( ) {
152
156
let mut sub_unifier = Unifier :: new ( self . sub ) ;
153
157
while let Some ( ( expected, actual) ) = self . delayed_records . pop ( ) {
@@ -160,6 +164,51 @@ impl<'a, E> Unifier<'a, E> {
160
164
. extend ( sub_unifier. errors . into_iter ( ) . map ( & mk_error) ) ;
161
165
}
162
166
167
+ struct FindUnboundLabels < ' a > {
168
+ found : RefCell < Option < MonoType > > ,
169
+ sub : & ' a dyn Substituter ,
170
+ }
171
+ impl Substituter for FindUnboundLabels < ' _ > {
172
+ fn try_apply ( & self , _: Tvar ) -> Option < MonoType > {
173
+ None
174
+ }
175
+ fn visit_type ( & self , typ : & MonoType ) -> Option < MonoType > {
176
+ if let MonoType :: Record ( rec) = typ {
177
+ if let Record :: Extension {
178
+ head :
179
+ Property {
180
+ k : RecordLabel :: Variable ( var) ,
181
+ ..
182
+ } ,
183
+ ..
184
+ } = & * * rec
185
+ {
186
+ match self . sub . try_apply ( * var) {
187
+ Some ( MonoType :: Var ( _) ) | None => {
188
+ * self . found . borrow_mut ( ) = Some ( MonoType :: Var ( * var) )
189
+ }
190
+ _ => ( ) ,
191
+ }
192
+ }
193
+ }
194
+ None
195
+ }
196
+ }
197
+
198
+ let mut error_on_unbound_record_labels = |typ : & MonoType | {
199
+ let visitor = FindUnboundLabels {
200
+ found : RefCell :: new ( None ) ,
201
+ sub : self . sub ,
202
+ } ;
203
+ let typ = typ. apply_cow ( self . sub ) ;
204
+ typ. visit ( & visitor) ;
205
+ if let Some ( non_label) = visitor. found . into_inner ( ) {
206
+ self . errors . push ( mk_error ( Error :: NotALabel ( non_label) ) ) ;
207
+ }
208
+ } ;
209
+
210
+ error_on_unbound_record_labels ( & value) ;
211
+
163
212
if self . errors . has_errors ( ) {
164
213
Err ( self . errors )
165
214
} else {
@@ -1484,6 +1533,7 @@ impl Record {
1484
1533
RecordLabel :: Concrete ( _) => unifier. errors . push ( Error :: MissingLabel ( a. to_string ( ) ) ) ,
1485
1534
RecordLabel :: BoundVariable ( v) | RecordLabel :: Variable ( v) => {
1486
1535
let t = unifier. sub . apply ( v) ;
1536
+ t. unify ( & MonoType :: Error , unifier) ;
1487
1537
unifier. errors . push ( Error :: NotALabel ( t) ) ;
1488
1538
}
1489
1539
} ,
@@ -1999,7 +2049,8 @@ impl Function {
1999
2049
2000
2050
self . unify ( actual, & mut unifier) ;
2001
2051
2002
- unifier. finish ( ( ) , mk_error)
2052
+ unifier. finish ( MonoType :: from ( self . clone ( ) ) , mk_error) ?;
2053
+ Ok ( ( ) )
2003
2054
}
2004
2055
2005
2056
pub ( crate ) fn try_subsume_with < T > (
@@ -2015,7 +2066,8 @@ impl Function {
2015
2066
2016
2067
self . unify ( actual, & mut unifier) ;
2017
2068
2018
- unifier. finish ( ( ) , mk_error)
2069
+ unifier. finish ( MonoType :: from ( self . clone ( ) ) , mk_error) ?;
2070
+ Ok ( ( ) )
2019
2071
}
2020
2072
2021
2073
/// Given two function types f and g, the process for unifying their arguments is as follows:
0 commit comments