@@ -1046,19 +1046,12 @@ impl<'interner, 'arena> Context<'interner, 'arena> {
10461046 let ( synth_term, synth_type) = self . synth_and_insert_implicit_apps ( surface_term) ;
10471047 self . coerce ( surface_range, synth_term, & synth_type, & expected_type)
10481048 }
1049- ( Term :: RecordLiteral ( _ , expr_fields) , Value :: RecordType ( labels, types) ) => {
1049+ ( Term :: RecordLiteral ( range , expr_fields) , Value :: RecordType ( labels, types) ) => {
10501050 // TODO: improve handling of duplicate labels
1051- if expr_fields . len ( ) != labels . len ( )
1052- || Iterator :: zip ( expr_fields . iter ( ) , labels. iter ( ) )
1053- . any ( | ( expr_field , type_label ) | expr_field . label . 1 != * type_label )
1051+ if self
1052+ . check_record_fields ( * range , expr_fields , |field| field . label , labels)
1053+ . is_err ( )
10541054 {
1055- self . push_message ( Message :: MismatchedFieldLabels {
1056- range : file_range,
1057- expr_labels : ( expr_fields. iter ( ) )
1058- . map ( |ExprField { label, .. } | ( self . file_range ( label. 0 ) , label. 1 ) )
1059- . collect ( ) ,
1060- type_labels : labels. to_vec ( ) ,
1061- } ) ;
10621055 return core:: Term :: Prim ( file_range. into ( ) , Prim :: ReportedError ) ;
10631056 }
10641057
@@ -1121,33 +1114,11 @@ impl<'interner, 'arena> Context<'interner, 'arena> {
11211114 core:: Term :: FormatRecord ( file_range. into ( ) , labels, formats)
11221115 } )
11231116 }
1124- ( Term :: Tuple ( _, elem_exprs) , Value :: RecordType ( labels, types) ) => {
1125- if elem_exprs. len ( ) != labels. len ( ) {
1126- let mut expr_labels = Vec :: with_capacity ( elem_exprs. len ( ) ) ;
1127- let mut elem_exprs = elem_exprs. iter ( ) . enumerate ( ) . peekable ( ) ;
1128- let mut label_iter = labels. iter ( ) ;
1129-
1130- // use the label names from the expected type
1131- while let Some ( ( ( _, elem_expr) , label) ) =
1132- Option :: zip ( elem_exprs. peek ( ) , label_iter. next ( ) )
1133- {
1134- expr_labels. push ( ( self . file_range ( elem_expr. range ( ) ) , * label) ) ;
1135- elem_exprs. next ( ) ;
1136- }
1137-
1138- // use numeric labels for excess elems
1139- for ( index, elem_expr) in elem_exprs {
1140- expr_labels. push ( (
1141- self . file_range ( elem_expr. range ( ) ) ,
1142- self . interner . borrow_mut ( ) . get_tuple_label ( index) ,
1143- ) ) ;
1144- }
1145-
1146- self . push_message ( Message :: MismatchedFieldLabels {
1147- range : file_range,
1148- expr_labels,
1149- type_labels : labels. to_vec ( ) ,
1150- } ) ;
1117+ ( Term :: Tuple ( range, elem_exprs) , Value :: RecordType ( labels, types) ) => {
1118+ if self
1119+ . check_tuple_fields ( * range, elem_exprs, |term| term. range ( ) , labels)
1120+ . is_err ( )
1121+ {
11511122 return core:: Term :: Prim ( file_range. into ( ) , Prim :: ReportedError ) ;
11521123 }
11531124
@@ -2218,6 +2189,76 @@ impl<'interner, 'arena> Context<'interner, 'arena> {
22182189 ( labels, formats. into ( ) )
22192190 }
22202191
2192+ fn check_tuple_fields < F > (
2193+ & mut self ,
2194+ range : ByteRange ,
2195+ fields : & [ F ] ,
2196+ get_range : fn ( & F ) -> ByteRange ,
2197+ expected_labels : & [ StringId ] ,
2198+ ) -> Result < ( ) , ( ) > {
2199+ if fields. len ( ) == expected_labels. len ( ) {
2200+ return Ok ( ( ) ) ;
2201+ }
2202+
2203+ let mut found_labels = Vec :: with_capacity ( fields. len ( ) ) ;
2204+ let mut fields_iter = fields. iter ( ) . enumerate ( ) . peekable ( ) ;
2205+ let mut expected_labels_iter = expected_labels. iter ( ) ;
2206+
2207+ // use the label names from the expected labels
2208+ while let Some ( ( ( _, field) , label) ) =
2209+ Option :: zip ( fields_iter. peek ( ) , expected_labels_iter. next ( ) )
2210+ {
2211+ found_labels. push ( ( self . file_range ( get_range ( field) ) , * label) ) ;
2212+ fields_iter. next ( ) ;
2213+ }
2214+
2215+ // use numeric labels for excess fields
2216+ for ( index, field) in fields_iter {
2217+ found_labels. push ( (
2218+ self . file_range ( get_range ( field) ) ,
2219+ self . interner . borrow_mut ( ) . get_tuple_label ( index) ,
2220+ ) ) ;
2221+ }
2222+
2223+ self . push_message ( Message :: MismatchedFieldLabels {
2224+ range : self . file_range ( range) ,
2225+ found_labels,
2226+ expected_labels : expected_labels. to_vec ( ) ,
2227+ } ) ;
2228+ Err ( ( ) )
2229+ }
2230+
2231+ fn check_record_fields < F > (
2232+ & mut self ,
2233+ range : ByteRange ,
2234+ fields : & [ F ] ,
2235+ get_label : impl Fn ( & F ) -> ( ByteRange , StringId ) ,
2236+ labels : & ' arena [ StringId ] ,
2237+ ) -> Result < ( ) , ( ) > {
2238+ if fields. len ( ) == labels. len ( )
2239+ && fields
2240+ . iter ( )
2241+ . zip ( labels. iter ( ) )
2242+ . all ( |( field, type_label) | get_label ( field) . 1 == * type_label)
2243+ {
2244+ return Ok ( ( ) ) ;
2245+ }
2246+
2247+ // TODO: improve handling of duplicate labels
2248+ self . push_message ( Message :: MismatchedFieldLabels {
2249+ range : self . file_range ( range) ,
2250+ found_labels : fields
2251+ . iter ( )
2252+ . map ( |field| {
2253+ let ( range, label) = get_label ( field) ;
2254+ ( self . file_range ( range) , label)
2255+ } )
2256+ . collect ( ) ,
2257+ expected_labels : labels. to_vec ( ) ,
2258+ } ) ;
2259+ Err ( ( ) )
2260+ }
2261+
22212262 /// Elaborate a match expression in checking mode
22222263 fn check_match (
22232264 & mut self ,
0 commit comments