@@ -264,6 +264,18 @@ function initSearch(rawSearchIndex) {
264264 * Special type name IDs for searching by both array and slice (`[]` syntax).
265265 */
266266 let typeNameIdOfArrayOrSlice ;
267+ /**
268+ * Special type name IDs for searching by tuple.
269+ */
270+ let typeNameIdOfTuple ;
271+ /**
272+ * Special type name IDs for searching by unit.
273+ */
274+ let typeNameIdOfUnit ;
275+ /**
276+ * Special type name IDs for searching by both tuple and unit (`()` syntax).
277+ */
278+ let typeNameIdOfTupleOrUnit ;
267279
268280 /**
269281 * Add an item to the type Name->ID map, or, if one already exists, use it.
@@ -299,11 +311,7 @@ function initSearch(rawSearchIndex) {
299311 }
300312
301313 function isEndCharacter ( c ) {
302- return "=,>-]" . indexOf ( c ) !== - 1 ;
303- }
304-
305- function isErrorCharacter ( c ) {
306- return "()" . indexOf ( c ) !== - 1 ;
314+ return "=,>-])" . indexOf ( c ) !== - 1 ;
307315 }
308316
309317 function itemTypeFromName ( typename ) {
@@ -586,8 +594,6 @@ function initSearch(rawSearchIndex) {
586594 throw [ "Unexpected " , "!" , ": it can only be at the end of an ident" ] ;
587595 }
588596 foundExclamation = parserState . pos ;
589- } else if ( isErrorCharacter ( c ) ) {
590- throw [ "Unexpected " , c ] ;
591597 } else if ( isPathSeparator ( c ) ) {
592598 if ( c === ":" ) {
593599 if ( ! isPathStart ( parserState ) ) {
@@ -617,11 +623,14 @@ function initSearch(rawSearchIndex) {
617623 }
618624 } else if (
619625 c === "[" ||
626+ c === "(" ||
620627 isEndCharacter ( c ) ||
621628 isSpecialStartCharacter ( c ) ||
622629 isSeparatorCharacter ( c )
623630 ) {
624631 break ;
632+ } else if ( parserState . pos > 0 ) {
633+ throw [ "Unexpected " , c , " after " , parserState . userQuery [ parserState . pos - 1 ] ] ;
625634 } else {
626635 throw [ "Unexpected " , c ] ;
627636 }
@@ -662,42 +671,55 @@ function initSearch(rawSearchIndex) {
662671 skipWhitespace ( parserState ) ;
663672 let start = parserState . pos ;
664673 let end ;
665- if ( parserState . userQuery [ parserState . pos ] === "[" ) {
674+ if ( "[(" . indexOf ( parserState . userQuery [ parserState . pos ] ) !== - 1 ) {
675+ let endChar = ")" ;
676+ let name = "()" ;
677+ let friendlyName = "tuple" ;
678+
679+ if ( parserState . userQuery [ parserState . pos ] === "[" ) {
680+ endChar = "]" ;
681+ name = "[]" ;
682+ friendlyName = "slice" ;
683+ }
666684 parserState . pos += 1 ;
667- getItemsBefore ( query , parserState , generics , "]" ) ;
685+ const { foundSeparator } = getItemsBefore ( query , parserState , generics , endChar ) ;
668686 const typeFilter = parserState . typeFilter ;
669687 const isInBinding = parserState . isInBinding ;
670688 if ( typeFilter !== null && typeFilter !== "primitive" ) {
671689 throw [
672690 "Invalid search type: primitive " ,
673- "[]" ,
691+ name ,
674692 " and " ,
675693 typeFilter ,
676694 " both specified" ,
677695 ] ;
678696 }
679697 parserState . typeFilter = null ;
680698 parserState . isInBinding = null ;
681- parserState . totalElems += 1 ;
682- if ( isInGenerics ) {
683- parserState . genericsElems += 1 ;
684- }
685699 for ( const gen of generics ) {
686700 if ( gen . bindingName !== null ) {
687- throw [ "Type parameter " , "=" , " cannot be within slice " , "[]" ] ;
701+ throw [ "Type parameter " , "=" , ` cannot be within ${ friendlyName } ` , name ] ;
688702 }
689703 }
690- elems . push ( {
691- name : "[]" ,
692- id : null ,
693- fullPath : [ "[]" ] ,
694- pathWithoutLast : [ ] ,
695- pathLast : "[]" ,
696- generics,
697- typeFilter : "primitive" ,
698- bindingName : isInBinding ,
699- bindings : new Map ( ) ,
700- } ) ;
704+ if ( name === "()" && ! foundSeparator && generics . length === 1 && typeFilter === null ) {
705+ elems . push ( generics [ 0 ] ) ;
706+ } else {
707+ parserState . totalElems += 1 ;
708+ if ( isInGenerics ) {
709+ parserState . genericsElems += 1 ;
710+ }
711+ elems . push ( {
712+ name : name ,
713+ id : null ,
714+ fullPath : [ name ] ,
715+ pathWithoutLast : [ ] ,
716+ pathLast : 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 ) ) {
@@ -1600,6 +1631,11 @@ function initSearch(rawSearchIndex) {
16001631 ) {
16011632 // [] matches primitive:array or primitive:slice
16021633 // if it matches, then we're fine, and this is an appropriate match candidate
1634+ } else if ( queryElem . id === typeNameIdOfTupleOrUnit &&
1635+ ( fnType . id === typeNameIdOfTuple || fnType . id === typeNameIdOfUnit )
1636+ ) {
1637+ // () matches primitive:tuple or primitive:unit
1638+ // if it matches, then we're fine, and this is an appropriate match candidate
16031639 } else if ( fnType . id !== queryElem . id || queryElem . id === null ) {
16041640 return false ;
16051641 }
@@ -1793,7 +1829,7 @@ function initSearch(rawSearchIndex) {
17931829 if ( row . id > 0 && elem . id > 0 && elem . pathWithoutLast . length === 0 &&
17941830 typePassesFilter ( elem . typeFilter , row . ty ) && elem . generics . length === 0 &&
17951831 // special case
1796- elem . id !== typeNameIdOfArrayOrSlice
1832+ elem . id !== typeNameIdOfArrayOrSlice && elem . id !== typeNameIdOfTupleOrUnit
17971833 ) {
17981834 return row . id === elem . id || checkIfInList (
17991835 row . generics ,
@@ -2834,12 +2870,15 @@ ${item.displayPath}<span class="${type}">${name}</span>\
28342870 */
28352871 function buildFunctionTypeFingerprint ( type , output , fps ) {
28362872 let input = type . id ;
2837- // All forms of `[]` get collapsed down to one thing in the bloom filter.
2873+ // All forms of `[]`/`()` get collapsed down to one thing in the bloom filter.
28382874 // Differentiating between arrays and slices, if the user asks for it, is
28392875 // still done in the matching algorithm.
28402876 if ( input === typeNameIdOfArray || input === typeNameIdOfSlice ) {
28412877 input = typeNameIdOfArrayOrSlice ;
28422878 }
2879+ if ( input === typeNameIdOfTuple || input === typeNameIdOfUnit ) {
2880+ input = typeNameIdOfTupleOrUnit ;
2881+ }
28432882 // http://burtleburtle.net/bob/hash/integer.html
28442883 // ~~ is toInt32. It's used before adding, so
28452884 // the number stays in safe integer range.
@@ -2940,7 +2979,10 @@ ${item.displayPath}<span class="${type}">${name}</span>\
29402979 // that can be searched using `[]` syntax.
29412980 typeNameIdOfArray = buildTypeMapIndex ( "array" ) ;
29422981 typeNameIdOfSlice = buildTypeMapIndex ( "slice" ) ;
2982+ typeNameIdOfTuple = buildTypeMapIndex ( "tuple" ) ;
2983+ typeNameIdOfUnit = buildTypeMapIndex ( "unit" ) ;
29432984 typeNameIdOfArrayOrSlice = buildTypeMapIndex ( "[]" ) ;
2985+ typeNameIdOfTupleOrUnit = buildTypeMapIndex ( "()" ) ;
29442986
29452987 // Function type fingerprints are 128-bit bloom filters that are used to
29462988 // estimate the distance between function and query.
0 commit comments