@@ -260,6 +260,18 @@ function initSearch(rawSearchIndex) {
260
260
* Special type name IDs for searching by both array and slice (`[]` syntax).
261
261
*/
262
262
let typeNameIdOfArrayOrSlice ;
263
+ /**
264
+ * Special type name IDs for searching by tuple.
265
+ */
266
+ let typeNameIdOfTuple ;
267
+ /**
268
+ * Special type name IDs for searching by unit.
269
+ */
270
+ let typeNameIdOfUnit ;
271
+ /**
272
+ * Special type name IDs for searching by both tuple and unit (`()` syntax).
273
+ */
274
+ let typeNameIdOfTupleOrUnit ;
263
275
264
276
/**
265
277
* Add an item to the type Name->ID map, or, if one already exists, use it.
@@ -295,11 +307,7 @@ function initSearch(rawSearchIndex) {
295
307
}
296
308
297
309
function isEndCharacter ( c ) {
298
- return "=,>-]" . indexOf ( c ) !== - 1 ;
299
- }
300
-
301
- function isErrorCharacter ( c ) {
302
- return "()" . indexOf ( c ) !== - 1 ;
310
+ return "=,>-])" . indexOf ( c ) !== - 1 ;
303
311
}
304
312
305
313
function itemTypeFromName ( typename ) {
@@ -585,8 +593,6 @@ function initSearch(rawSearchIndex) {
585
593
throw [ "Unexpected " , "!" , ": it can only be at the end of an ident" ] ;
586
594
}
587
595
foundExclamation = parserState . pos ;
588
- } else if ( isErrorCharacter ( c ) ) {
589
- throw [ "Unexpected " , c ] ;
590
596
} else if ( isPathSeparator ( c ) ) {
591
597
if ( c === ":" ) {
592
598
if ( ! isPathStart ( parserState ) ) {
@@ -616,11 +622,14 @@ function initSearch(rawSearchIndex) {
616
622
}
617
623
} else if (
618
624
c === "[" ||
625
+ c === "(" ||
619
626
isEndCharacter ( c ) ||
620
627
isSpecialStartCharacter ( c ) ||
621
628
isSeparatorCharacter ( c )
622
629
) {
623
630
break ;
631
+ } else if ( parserState . pos > 0 ) {
632
+ throw [ "Unexpected " , c , " after " , parserState . userQuery [ parserState . pos - 1 ] ] ;
624
633
} else {
625
634
throw [ "Unexpected " , c ] ;
626
635
}
@@ -661,43 +670,56 @@ function initSearch(rawSearchIndex) {
661
670
skipWhitespace ( parserState ) ;
662
671
let start = parserState . pos ;
663
672
let end ;
664
- if ( parserState . userQuery [ parserState . pos ] === "[" ) {
673
+ if ( "[(" . indexOf ( parserState . userQuery [ parserState . pos ] ) !== - 1 ) {
674
+ let endChar = ")" ;
675
+ let name = "()" ;
676
+ let friendlyName = "tuple" ;
677
+
678
+ if ( parserState . userQuery [ parserState . pos ] === "[" ) {
679
+ endChar = "]" ;
680
+ name = "[]" ;
681
+ friendlyName = "slice" ;
682
+ }
665
683
parserState . pos += 1 ;
666
- getItemsBefore ( query , parserState , generics , "]" ) ;
684
+ const { foundSeparator } = getItemsBefore ( query , parserState , generics , endChar ) ;
667
685
const typeFilter = parserState . typeFilter ;
668
686
const isInBinding = parserState . isInBinding ;
669
687
if ( typeFilter !== null && typeFilter !== "primitive" ) {
670
688
throw [
671
689
"Invalid search type: primitive " ,
672
- "[]" ,
690
+ name ,
673
691
" and " ,
674
692
typeFilter ,
675
693
" both specified" ,
676
694
] ;
677
695
}
678
696
parserState . typeFilter = null ;
679
697
parserState . isInBinding = null ;
680
- parserState . totalElems += 1 ;
681
- if ( isInGenerics ) {
682
- parserState . genericsElems += 1 ;
683
- }
684
698
for ( const gen of generics ) {
685
699
if ( gen . bindingName !== null ) {
686
- throw [ "Type parameter " , "=" , " cannot be within slice " , "[]" ] ;
700
+ throw [ "Type parameter " , "=" , ` cannot be within ${ friendlyName } ` , name ] ;
687
701
}
688
702
}
689
- elems . push ( {
690
- name : "[]" ,
691
- id : null ,
692
- fullPath : [ "[]" ] ,
693
- pathWithoutLast : [ ] ,
694
- pathLast : "[]" ,
695
- normalizedPathLast : "[]" ,
696
- generics,
697
- typeFilter : "primitive" ,
698
- bindingName : isInBinding ,
699
- bindings : new Map ( ) ,
700
- } ) ;
703
+ if ( name === "()" && ! foundSeparator && generics . length === 1 && typeFilter === null ) {
704
+ elems . push ( generics [ 0 ] ) ;
705
+ } else {
706
+ parserState . totalElems += 1 ;
707
+ if ( isInGenerics ) {
708
+ parserState . genericsElems += 1 ;
709
+ }
710
+ elems . push ( {
711
+ name : name ,
712
+ id : null ,
713
+ fullPath : [ name ] ,
714
+ pathWithoutLast : [ ] ,
715
+ pathLast : name ,
716
+ normalizedPathLast : name ,
717
+ generics,
718
+ bindings : new Map ( ) ,
719
+ typeFilter : "primitive" ,
720
+ bindingName : isInBinding ,
721
+ } ) ;
722
+ }
701
723
} else {
702
724
const isStringElem = parserState . userQuery [ start ] === "\"" ;
703
725
// We handle the strings on their own mostly to make code easier to follow.
@@ -770,9 +792,11 @@ function initSearch(rawSearchIndex) {
770
792
* @param {Array<QueryElement> } elems - This is where the new {QueryElement} will be added.
771
793
* @param {string } endChar - This function will stop when it'll encounter this
772
794
* character.
795
+ * @returns {{foundSeparator: bool} }
773
796
*/
774
797
function getItemsBefore ( query , parserState , elems , endChar ) {
775
798
let foundStopChar = true ;
799
+ let foundSeparator = false ;
776
800
let start = parserState . pos ;
777
801
778
802
// If this is a generic, keep the outer item's type filter around.
@@ -786,6 +810,8 @@ function initSearch(rawSearchIndex) {
786
810
extra = "<" ;
787
811
} else if ( endChar === "]" ) {
788
812
extra = "[" ;
813
+ } else if ( endChar === ")" ) {
814
+ extra = "(" ;
789
815
} else if ( endChar === "" ) {
790
816
extra = "->" ;
791
817
} else {
@@ -802,6 +828,7 @@ function initSearch(rawSearchIndex) {
802
828
} else if ( isSeparatorCharacter ( c ) ) {
803
829
parserState . pos += 1 ;
804
830
foundStopChar = true ;
831
+ foundSeparator = true ;
805
832
continue ;
806
833
} else if ( c === ":" && isPathStart ( parserState ) ) {
807
834
throw [ "Unexpected " , "::" , ": paths cannot start with " , "::" ] ;
@@ -879,6 +906,8 @@ function initSearch(rawSearchIndex) {
879
906
880
907
parserState . typeFilter = oldTypeFilter ;
881
908
parserState . isInBinding = oldIsInBinding ;
909
+
910
+ return { foundSeparator } ;
882
911
}
883
912
884
913
/**
@@ -926,6 +955,8 @@ function initSearch(rawSearchIndex) {
926
955
break ;
927
956
}
928
957
throw [ "Unexpected " , c , " (did you mean " , "->" , "?)" ] ;
958
+ } else if ( parserState . pos > 0 ) {
959
+ throw [ "Unexpected " , c , " after " , parserState . userQuery [ parserState . pos - 1 ] ] ;
929
960
}
930
961
throw [ "Unexpected " , c ] ;
931
962
} else if ( c === ":" && ! isPathStart ( parserState ) ) {
@@ -1599,6 +1630,11 @@ function initSearch(rawSearchIndex) {
1599
1630
) {
1600
1631
// [] matches primitive:array or primitive:slice
1601
1632
// if it matches, then we're fine, and this is an appropriate match candidate
1633
+ } else if ( queryElem . id === typeNameIdOfTupleOrUnit &&
1634
+ ( fnType . id === typeNameIdOfTuple || fnType . id === typeNameIdOfUnit )
1635
+ ) {
1636
+ // () matches primitive:tuple or primitive:unit
1637
+ // if it matches, then we're fine, and this is an appropriate match candidate
1602
1638
} else if ( fnType . id !== queryElem . id || queryElem . id === null ) {
1603
1639
return false ;
1604
1640
}
@@ -1792,7 +1828,7 @@ function initSearch(rawSearchIndex) {
1792
1828
if ( row . id > 0 && elem . id > 0 && elem . pathWithoutLast . length === 0 &&
1793
1829
typePassesFilter ( elem . typeFilter , row . ty ) && elem . generics . length === 0 &&
1794
1830
// special case
1795
- elem . id !== typeNameIdOfArrayOrSlice
1831
+ elem . id !== typeNameIdOfArrayOrSlice && elem . id !== typeNameIdOfTupleOrUnit
1796
1832
) {
1797
1833
return row . id === elem . id || checkIfInList (
1798
1834
row . generics ,
@@ -2886,12 +2922,15 @@ ${item.displayPath}<span class="${type}">${name}</span>\
2886
2922
*/
2887
2923
function buildFunctionTypeFingerprint ( type , output , fps ) {
2888
2924
let input = type . id ;
2889
- // All forms of `[]` get collapsed down to one thing in the bloom filter.
2925
+ // All forms of `[]`/`()` get collapsed down to one thing in the bloom filter.
2890
2926
// Differentiating between arrays and slices, if the user asks for it, is
2891
2927
// still done in the matching algorithm.
2892
2928
if ( input === typeNameIdOfArray || input === typeNameIdOfSlice ) {
2893
2929
input = typeNameIdOfArrayOrSlice ;
2894
2930
}
2931
+ if ( input === typeNameIdOfTuple || input === typeNameIdOfUnit ) {
2932
+ input = typeNameIdOfTupleOrUnit ;
2933
+ }
2895
2934
// http://burtleburtle.net/bob/hash/integer.html
2896
2935
// ~~ is toInt32. It's used before adding, so
2897
2936
// the number stays in safe integer range.
@@ -2991,7 +3030,10 @@ ${item.displayPath}<span class="${type}">${name}</span>\
2991
3030
// that can be searched using `[]` syntax.
2992
3031
typeNameIdOfArray = buildTypeMapIndex ( "array" ) ;
2993
3032
typeNameIdOfSlice = buildTypeMapIndex ( "slice" ) ;
3033
+ typeNameIdOfTuple = buildTypeMapIndex ( "tuple" ) ;
3034
+ typeNameIdOfUnit = buildTypeMapIndex ( "unit" ) ;
2994
3035
typeNameIdOfArrayOrSlice = buildTypeMapIndex ( "[]" ) ;
3036
+ typeNameIdOfTupleOrUnit = buildTypeMapIndex ( "()" ) ;
2995
3037
2996
3038
// Function type fingerprints are 128-bit bloom filters that are used to
2997
3039
// estimate the distance between function and query.
0 commit comments