@@ -11,8 +11,8 @@ use super::*;
11
11
use crate :: {
12
12
analyse:: { self , Inferred , name:: check_name_case} ,
13
13
ast:: {
14
- AssignName , BitArrayOption , BitArraySize , ImplicitCallArgOrigin , Layer , TypedBitArraySize ,
15
- UntypedPatternBitArraySegment ,
14
+ AssignName , BitArrayOption , BitArraySize , ImplicitCallArgOrigin , Layer , Pattern ,
15
+ TypedBitArraySize , UntypedPatternBitArraySegment ,
16
16
} ,
17
17
parse:: PatternPosition ,
18
18
reference:: ReferenceKind ,
@@ -911,78 +911,11 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
911
911
self . error_encountered = true ;
912
912
} ;
913
913
}
914
-
915
- // Insert discard variables to match the unspecified fields
916
- // In order to support both positional and labelled arguments we have to insert
917
- // them after all positional variables and before the labelled ones. This means
918
- // we have calculate that index and then insert() the discards. It would be faster
919
- // if we could put the discards anywhere which would let us use push().
920
- // Potential future optimisation.
921
- let index_of_first_labelled_arg = pattern_arguments
922
- . iter ( )
923
- . position ( |argument| argument. label . is_some ( ) )
924
- . unwrap_or ( pattern_arguments. len ( ) ) ;
925
-
926
- // In Gleam we can pass in positional unlabelled args to a constructor
927
- // even if the field was defined as labelled
928
- //
929
- // pub type Wibble {
930
- // Wibble(Int, two: Int, three: Int, four: Int)
931
- // }
932
- // Wibble(1, 2, 3, 4)
933
- //
934
- // When using `..` to ignore some fields the compiler needs to add a
935
- // placeholder implicit discard pattern for each one of the ignored
936
- // arguments. To give those discards the proper missing label we need to
937
- // know how many of the labelled fields were provided as unlabelled.
938
- //
939
- // That's why we want to keep track of the number of unlabelled argument
940
- // that have been supplied to the pattern and all the labels that have
941
- // been explicitly supplied.
942
- //
943
- // Wibble(a, b, four: c, ..)
944
- // ┬─── ┬──────
945
- // │ ╰ We supplied 1 labelled arg
946
- // ╰ We supplied 2 unlabelled args
947
- //
948
- let supplied_unlabelled_arguments = index_of_first_labelled_arg;
949
- let supplied_labelled_arguments = pattern_arguments
950
- . iter ( )
951
- . filter_map ( |argument| argument. label . clone ( ) )
952
- . collect :: < HashSet < _ > > ( ) ;
953
- let constructor_unlabelled_arguments =
954
- field_map. arity - field_map. fields . len ( ) as u32 ;
955
- let labelled_arguments_supplied_as_unlabelled =
956
- supplied_unlabelled_arguments
957
- . saturating_sub ( constructor_unlabelled_arguments as usize ) ;
958
-
959
- let mut missing_labels = field_map
960
- . fields
961
- . iter ( )
962
- // We take the labels in order of definition in the constructor...
963
- . sorted_by_key ( |( _, position) | * position)
964
- . map ( |( label, _) | label. clone ( ) )
965
- // ...and then remove the ones that were supplied as unlabelled
966
- // positional arguments...
967
- . skip ( labelled_arguments_supplied_as_unlabelled)
968
- // ... lastly we still need to remove all those labels that
969
- // were explicitly supplied in the pattern.
970
- . filter ( |label| !supplied_labelled_arguments. contains ( label) ) ;
971
-
972
- while pattern_arguments. len ( ) < field_map. arity as usize {
973
- let new_call_arg = CallArg {
974
- value : Pattern :: Discard {
975
- name : "_" . into ( ) ,
976
- location : spread_location,
977
- type_ : ( ) ,
978
- } ,
979
- location : spread_location,
980
- label : missing_labels. next ( ) ,
981
- implicit : Some ( ImplicitCallArgOrigin :: PatternFieldSpread ) ,
982
- } ;
983
-
984
- pattern_arguments. insert ( index_of_first_labelled_arg, new_call_arg) ;
985
- }
914
+ insert_spread_call_arguments (
915
+ & mut pattern_arguments,
916
+ field_map,
917
+ spread_location,
918
+ ) ;
986
919
}
987
920
988
921
if let Err ( error) = field_map. reorder (
@@ -993,6 +926,13 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
993
926
incorrect_arity_error = true ;
994
927
self . problems . error ( error) ;
995
928
self . error_encountered = true ;
929
+ // Since we reported the arity error now, we can pretend
930
+ // that `..` is now added, so other errors will not be affected.
931
+ insert_spread_call_arguments (
932
+ & mut pattern_arguments,
933
+ field_map,
934
+ name_location,
935
+ ) ;
996
936
}
997
937
}
998
938
@@ -1115,7 +1055,6 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
1115
1055
1116
1056
let pattern_arguments =
1117
1057
self . infer_pattern_call_arguments ( pattern_arguments, arguments) ;
1118
-
1119
1058
Pattern :: Constructor {
1120
1059
location,
1121
1060
name_location,
@@ -1381,3 +1320,80 @@ fn unify_constructor_variants(into: &mut Type, from: &Type) {
1381
1320
_ => { }
1382
1321
}
1383
1322
}
1323
+
1324
+ /// Inserts needed discard variables to Constructor::Pattern, when `spread` is used.
1325
+ fn insert_spread_call_arguments (
1326
+ pattern_arguments : & mut Vec < CallArg < Pattern < ( ) > > > ,
1327
+ field_map : & FieldMap ,
1328
+ location : SrcSpan ,
1329
+ ) {
1330
+ // Insert discard variables to match the unspecified fields
1331
+ // In order to support both positional and labelled arguments we have to insert
1332
+ // them after all positional variables and before the labelled ones. This means
1333
+ // we have calculate that index and then insert() the discards. It would be faster
1334
+ // if we could put the discards anywhere which would let us use push().
1335
+ // Potential future optimisation.
1336
+ let index_of_first_labelled_arg = pattern_arguments
1337
+ . iter ( )
1338
+ . position ( |argument| argument. label . is_some ( ) )
1339
+ . unwrap_or ( pattern_arguments. len ( ) ) ;
1340
+
1341
+ // In Gleam we can pass in positional unlabelled args to a constructor
1342
+ // even if the field was defined as labelled
1343
+ //
1344
+ // pub type Wibble {
1345
+ // Wibble(Int, two: Int, three: Int, four: Int)
1346
+ // }
1347
+ // Wibble(1, 2, 3, 4)
1348
+ //
1349
+ // When using `..` to ignore some fields the compiler needs to add a
1350
+ // placeholder implicit discard pattern for each one of the ignored
1351
+ // arguments. To give those discards the proper missing label we need to
1352
+ // know how many of the labelled fields were provided as unlabelled.
1353
+ //
1354
+ // That's why we want to keep track of the number of unlabelled argument
1355
+ // that have been supplied to the pattern and all the labels that have
1356
+ // been explicitly supplied.
1357
+ //
1358
+ // Wibble(a, b, four: c, ..)
1359
+ // ┬─── ┬──────
1360
+ // │ ╰ We supplied 1 labelled arg
1361
+ // ╰ We supplied 2 unlabelled args
1362
+ //
1363
+ let supplied_unlabelled_arguments = index_of_first_labelled_arg;
1364
+ let supplied_labelled_arguments = pattern_arguments
1365
+ . iter ( )
1366
+ . filter_map ( |argument| argument. label . clone ( ) )
1367
+ . collect :: < HashSet < _ > > ( ) ;
1368
+ let constructor_unlabelled_arguments = field_map. arity - field_map. fields . len ( ) as u32 ;
1369
+ let labelled_arguments_supplied_as_unlabelled =
1370
+ supplied_unlabelled_arguments. saturating_sub ( constructor_unlabelled_arguments as usize ) ;
1371
+
1372
+ let mut missing_labels = field_map
1373
+ . fields
1374
+ . iter ( )
1375
+ // We take the labels in order of definition in the constructor...
1376
+ . sorted_by_key ( |( _, position) | * position)
1377
+ . map ( |( label, _) | label. clone ( ) )
1378
+ // ...and then remove the ones that were supplied as unlabelled
1379
+ // positional arguments...
1380
+ . skip ( labelled_arguments_supplied_as_unlabelled)
1381
+ // ... lastly we still need to remove all those labels that
1382
+ // were explicitly supplied in the pattern.
1383
+ . filter ( |label| !supplied_labelled_arguments. contains ( label) ) ;
1384
+
1385
+ while pattern_arguments. len ( ) < field_map. arity as usize {
1386
+ let new_call_arg = CallArg {
1387
+ value : Pattern :: Discard {
1388
+ name : "_" . into ( ) ,
1389
+ location,
1390
+ type_ : ( ) ,
1391
+ } ,
1392
+ location,
1393
+ label : missing_labels. next ( ) ,
1394
+ implicit : Some ( ImplicitCallArgOrigin :: PatternFieldSpread ) ,
1395
+ } ;
1396
+
1397
+ pattern_arguments. insert ( index_of_first_labelled_arg, new_call_arg) ;
1398
+ }
1399
+ }
0 commit comments