@@ -260,6 +260,18 @@ function initSearch(rawSearchIndex) {
260260 * Special type name IDs for searching by both array and slice (`[]` syntax).
261261 */
262262 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 ;
263275
264276 /**
265277 * Add an item to the type Name->ID map, or, if one already exists, use it.
@@ -295,11 +307,7 @@ function initSearch(rawSearchIndex) {
295307 }
296308
297309 function isEndCharacter ( c ) {
298- return "=,>-]" . indexOf ( c ) !== - 1 ;
299- }
300-
301- function isErrorCharacter ( c ) {
302- return "()" . indexOf ( c ) !== - 1 ;
310+ return "=,>-])" . indexOf ( c ) !== - 1 ;
303311 }
304312
305313 function itemTypeFromName ( typename ) {
@@ -585,8 +593,6 @@ function initSearch(rawSearchIndex) {
585593 throw [ "Unexpected " , "!" , ": it can only be at the end of an ident" ] ;
586594 }
587595 foundExclamation = parserState . pos ;
588- } else if ( isErrorCharacter ( c ) ) {
589- throw [ "Unexpected " , c ] ;
590596 } else if ( isPathSeparator ( c ) ) {
591597 if ( c === ":" ) {
592598 if ( ! isPathStart ( parserState ) ) {
@@ -616,11 +622,14 @@ function initSearch(rawSearchIndex) {
616622 }
617623 } else if (
618624 c === "[" ||
625+ c === "(" ||
619626 isEndCharacter ( c ) ||
620627 isSpecialStartCharacter ( c ) ||
621628 isSeparatorCharacter ( c )
622629 ) {
623630 break ;
631+ } else if ( parserState . pos > 0 ) {
632+ throw [ "Unexpected " , c , " after " , parserState . userQuery [ parserState . pos - 1 ] ] ;
624633 } else {
625634 throw [ "Unexpected " , c ] ;
626635 }
@@ -661,43 +670,56 @@ function initSearch(rawSearchIndex) {
661670 skipWhitespace ( parserState ) ;
662671 let start = parserState . pos ;
663672 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+ }
665683 parserState . pos += 1 ;
666- getItemsBefore ( query , parserState , generics , "]" ) ;
684+ const { foundSeparator } = getItemsBefore ( query , parserState , generics , endChar ) ;
667685 const typeFilter = parserState . typeFilter ;
668686 const isInBinding = parserState . isInBinding ;
669687 if ( typeFilter !== null && typeFilter !== "primitive" ) {
670688 throw [
671689 "Invalid search type: primitive " ,
672- "[]" ,
690+ name ,
673691 " and " ,
674692 typeFilter ,
675693 " both specified" ,
676694 ] ;
677695 }
678696 parserState . typeFilter = null ;
679697 parserState . isInBinding = null ;
680- parserState . totalElems += 1 ;
681- if ( isInGenerics ) {
682- parserState . genericsElems += 1 ;
683- }
684698 for ( const gen of generics ) {
685699 if ( gen . bindingName !== null ) {
686- throw [ "Type parameter " , "=" , " cannot be within slice " , "[]" ] ;
700+ throw [ "Type parameter " , "=" , ` cannot be within ${ friendlyName } ` , name ] ;
687701 }
688702 }
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+ }
701723 } else {
702724 const isStringElem = parserState . userQuery [ start ] === "\"" ;
703725 // We handle the strings on their own mostly to make code easier to follow.
@@ -770,9 +792,11 @@ function initSearch(rawSearchIndex) {
770792 * @param {Array<QueryElement> } elems - This is where the new {QueryElement} will be added.
771793 * @param {string } endChar - This function will stop when it'll encounter this
772794 * character.
795+ * @returns {{foundSeparator: bool} }
773796 */
774797 function getItemsBefore ( query , parserState , elems , endChar ) {
775798 let foundStopChar = true ;
799+ let foundSeparator = false ;
776800 let start = parserState . pos ;
777801
778802 // If this is a generic, keep the outer item's type filter around.
@@ -786,6 +810,8 @@ function initSearch(rawSearchIndex) {
786810 extra = "<" ;
787811 } else if ( endChar === "]" ) {
788812 extra = "[" ;
813+ } else if ( endChar === ")" ) {
814+ extra = "(" ;
789815 } else if ( endChar === "" ) {
790816 extra = "->" ;
791817 } else {
@@ -802,6 +828,7 @@ function initSearch(rawSearchIndex) {
802828 } else if ( isSeparatorCharacter ( c ) ) {
803829 parserState . pos += 1 ;
804830 foundStopChar = true ;
831+ foundSeparator = true ;
805832 continue ;
806833 } else if ( c === ":" && isPathStart ( parserState ) ) {
807834 throw [ "Unexpected " , "::" , ": paths cannot start with " , "::" ] ;
@@ -879,6 +906,8 @@ function initSearch(rawSearchIndex) {
879906
880907 parserState . typeFilter = oldTypeFilter ;
881908 parserState . isInBinding = oldIsInBinding ;
909+
910+ return { foundSeparator } ;
882911 }
883912
884913 /**
@@ -926,6 +955,8 @@ function initSearch(rawSearchIndex) {
926955 break ;
927956 }
928957 throw [ "Unexpected " , c , " (did you mean " , "->" , "?)" ] ;
958+ } else if ( parserState . pos > 0 ) {
959+ throw [ "Unexpected " , c , " after " , parserState . userQuery [ parserState . pos - 1 ] ] ;
929960 }
930961 throw [ "Unexpected " , c ] ;
931962 } else if ( c === ":" && ! isPathStart ( parserState ) ) {
@@ -1599,6 +1630,11 @@ function initSearch(rawSearchIndex) {
15991630 ) {
16001631 // [] matches primitive:array or primitive:slice
16011632 // 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
16021638 } else if ( fnType . id !== queryElem . id || queryElem . id === null ) {
16031639 return false ;
16041640 }
@@ -1792,7 +1828,7 @@ function initSearch(rawSearchIndex) {
17921828 if ( row . id > 0 && elem . id > 0 && elem . pathWithoutLast . length === 0 &&
17931829 typePassesFilter ( elem . typeFilter , row . ty ) && elem . generics . length === 0 &&
17941830 // special case
1795- elem . id !== typeNameIdOfArrayOrSlice
1831+ elem . id !== typeNameIdOfArrayOrSlice && elem . id !== typeNameIdOfTupleOrUnit
17961832 ) {
17971833 return row . id === elem . id || checkIfInList (
17981834 row . generics ,
@@ -2822,12 +2858,15 @@ ${item.displayPath}<span class="${type}">${name}</span>\
28222858 */
28232859 function buildFunctionTypeFingerprint ( type , output , fps ) {
28242860 let input = type . id ;
2825- // All forms of `[]` get collapsed down to one thing in the bloom filter.
2861+ // All forms of `[]`/`()` get collapsed down to one thing in the bloom filter.
28262862 // Differentiating between arrays and slices, if the user asks for it, is
28272863 // still done in the matching algorithm.
28282864 if ( input === typeNameIdOfArray || input === typeNameIdOfSlice ) {
28292865 input = typeNameIdOfArrayOrSlice ;
28302866 }
2867+ if ( input === typeNameIdOfTuple || input === typeNameIdOfUnit ) {
2868+ input = typeNameIdOfTupleOrUnit ;
2869+ }
28312870 // http://burtleburtle.net/bob/hash/integer.html
28322871 // ~~ is toInt32. It's used before adding, so
28332872 // the number stays in safe integer range.
@@ -2922,7 +2961,10 @@ ${item.displayPath}<span class="${type}">${name}</span>\
29222961 // that can be searched using `[]` syntax.
29232962 typeNameIdOfArray = buildTypeMapIndex ( "array" ) ;
29242963 typeNameIdOfSlice = buildTypeMapIndex ( "slice" ) ;
2964+ typeNameIdOfTuple = buildTypeMapIndex ( "tuple" ) ;
2965+ typeNameIdOfUnit = buildTypeMapIndex ( "unit" ) ;
29252966 typeNameIdOfArrayOrSlice = buildTypeMapIndex ( "[]" ) ;
2967+ typeNameIdOfTupleOrUnit = buildTypeMapIndex ( "()" ) ;
29262968
29272969 // Function type fingerprints are 128-bit bloom filters that are used to
29282970 // estimate the distance between function and query.
0 commit comments