@@ -42,7 +42,7 @@ type IdentifierSidemap = {
4242 functions : Map < IdentifierId , TInstruction < FunctionExpression > > ;
4343 manualMemos : Map < IdentifierId , ManualMemoCallee > ;
4444 react : Set < IdentifierId > ;
45- maybeDepsLists : Map < IdentifierId , Array < Place > > ;
45+ maybeDepsLists : Map < IdentifierId , { loc : SourceLocation ; deps : Array < Place > } > ;
4646 maybeDeps : Map < IdentifierId , ManualMemoDependency > ;
4747 optionals : Set < IdentifierId > ;
4848} ;
@@ -159,10 +159,10 @@ function collectTemporaries(
159159 }
160160 case 'ArrayExpression' : {
161161 if ( value . elements . every ( e => e . kind === 'Identifier' ) ) {
162- sidemap . maybeDepsLists . set (
163- instr . lvalue . identifier . id ,
164- value . elements as Array < Place > ,
165- ) ;
162+ sidemap . maybeDepsLists . set ( instr . lvalue . identifier . id , {
163+ loc : value . loc ,
164+ deps : value . elements as Array < Place > ,
165+ } ) ;
166166 }
167167 break ;
168168 }
@@ -182,6 +182,7 @@ function makeManualMemoizationMarkers(
182182 fnExpr : Place ,
183183 env : Environment ,
184184 depsList : Array < ManualMemoDependency > | null ,
185+ depsLoc : SourceLocation | null ,
185186 memoDecl : Place ,
186187 manualMemoId : number ,
187188) : [ TInstruction < StartMemoize > , TInstruction < FinishMemoize > ] {
@@ -197,6 +198,7 @@ function makeManualMemoizationMarkers(
197198 * as dependencies
198199 */
199200 deps : depsList ,
201+ depsLoc,
200202 loc : fnExpr . loc ,
201203 } ,
202204 effects : null ,
@@ -287,86 +289,85 @@ function extractManualMemoizationArgs(
287289 sidemap : IdentifierSidemap ,
288290 errors : CompilerError ,
289291) : {
290- fnPlace : Place | null ;
292+ fnPlace : Place ;
291293 depsList : Array < ManualMemoDependency > | null ;
292- } {
294+ depsLoc : SourceLocation | null ;
295+ } | null {
293296 const [ fnPlace , depsListPlace ] = instr . value . args as Array <
294297 Place | SpreadPattern | undefined
295298 > ;
296- if ( fnPlace == null ) {
299+ if ( fnPlace == null || fnPlace . kind !== 'Identifier' ) {
297300 errors . pushDiagnostic (
298301 CompilerDiagnostic . create ( {
299302 category : ErrorCategory . UseMemo ,
300303 reason : `Expected a callback function to be passed to ${ kind } ` ,
301- description : `Expected a callback function to be passed to ${ kind } ` ,
304+ description :
305+ kind === 'useCallback'
306+ ? 'The first argument to useCallback() must be a function to cache'
307+ : 'The first argument to useMemo() must be a function that calculates a result to cache' ,
302308 suggestions : null ,
303309 } ) . withDetails ( {
304310 kind : 'error' ,
305311 loc : instr . value . loc ,
306- message : `Expected a callback function to be passed to ${ kind } ` ,
312+ message :
313+ kind === 'useCallback'
314+ ? `Expected a callback function`
315+ : `Expected a memoization function` ,
307316 } ) ,
308317 ) ;
309- return { fnPlace : null , depsList : null } ;
318+ return null ;
310319 }
311- if ( fnPlace . kind === 'Spread' || depsListPlace ?. kind === 'Spread' ) {
320+ if ( depsListPlace == null ) {
321+ return {
322+ fnPlace,
323+ depsList : null ,
324+ depsLoc : null ,
325+ } ;
326+ }
327+ const maybeDepsList =
328+ depsListPlace . kind === 'Identifier'
329+ ? sidemap . maybeDepsLists . get ( depsListPlace . identifier . id )
330+ : null ;
331+ if ( maybeDepsList == null ) {
312332 errors . pushDiagnostic (
313333 CompilerDiagnostic . create ( {
314334 category : ErrorCategory . UseMemo ,
315- reason : `Unexpected spread argument to ${ kind } ` ,
316- description : `Unexpected spread argument to ${ kind } ` ,
335+ reason : `Expected the dependency list for ${ kind } to be an array literal ` ,
336+ description : `Expected the dependency list for ${ kind } to be an array literal ` ,
317337 suggestions : null ,
318338 } ) . withDetails ( {
319339 kind : 'error' ,
320- loc : instr . value . loc ,
321- message : `Unexpected spread argument to ${ kind } ` ,
340+ loc :
341+ depsListPlace ?. kind === 'Identifier' ? depsListPlace . loc : instr . loc ,
342+ message : `Expected the dependency list for ${ kind } to be an array literal` ,
322343 } ) ,
323344 ) ;
324- return { fnPlace : null , depsList : null } ;
345+ return null ;
325346 }
326- let depsList : Array < ManualMemoDependency > | null = null ;
327- if ( depsListPlace != null ) {
328- const maybeDepsList = sidemap . maybeDepsLists . get (
329- depsListPlace . identifier . id ,
330- ) ;
331- if ( maybeDepsList == null ) {
347+ const depsList : Array < ManualMemoDependency > = [ ] ;
348+ for ( const dep of maybeDepsList . deps ) {
349+ const maybeDep = sidemap . maybeDeps . get ( dep . identifier . id ) ;
350+ if ( maybeDep == null ) {
332351 errors . pushDiagnostic (
333352 CompilerDiagnostic . create ( {
334353 category : ErrorCategory . UseMemo ,
335- reason : `Expected the dependency list for ${ kind } to be an array literal ` ,
336- description : `Expected the dependency list for ${ kind } to be an array literal ` ,
354+ reason : `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`) ` ,
355+ description : `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`) ` ,
337356 suggestions : null ,
338357 } ) . withDetails ( {
339358 kind : 'error' ,
340- loc : depsListPlace . loc ,
341- message : `Expected the dependency list for ${ kind } to be an array literal ` ,
359+ loc : dep . loc ,
360+ message : `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`) ` ,
342361 } ) ,
343362 ) ;
344- return { fnPlace, depsList : null } ;
345- }
346- depsList = [ ] ;
347- for ( const dep of maybeDepsList ) {
348- const maybeDep = sidemap . maybeDeps . get ( dep . identifier . id ) ;
349- if ( maybeDep == null ) {
350- errors . pushDiagnostic (
351- CompilerDiagnostic . create ( {
352- category : ErrorCategory . UseMemo ,
353- reason : `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)` ,
354- description : `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)` ,
355- suggestions : null ,
356- } ) . withDetails ( {
357- kind : 'error' ,
358- loc : dep . loc ,
359- message : `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)` ,
360- } ) ,
361- ) ;
362- } else {
363- depsList . push ( maybeDep ) ;
364- }
363+ } else {
364+ depsList . push ( maybeDep ) ;
365365 }
366366 }
367367 return {
368368 fnPlace,
369369 depsList,
370+ depsLoc : maybeDepsList . loc ,
370371 } ;
371372}
372373
@@ -427,16 +428,17 @@ export function dropManualMemoization(
427428
428429 const manualMemo = sidemap . manualMemos . get ( id ) ;
429430 if ( manualMemo != null ) {
430- const { fnPlace , depsList } = extractManualMemoizationArgs (
431+ const memoDetails = extractManualMemoizationArgs (
431432 instr as TInstruction < CallExpression > | TInstruction < MethodCall > ,
432433 manualMemo . kind ,
433434 sidemap ,
434435 errors ,
435436 ) ;
436437
437- if ( fnPlace == null ) {
438+ if ( memoDetails == null ) {
438439 continue ;
439440 }
441+ const { fnPlace, depsList, depsLoc} = memoDetails ;
440442
441443 /**
442444 * Bailout on void return useMemos. This is an anti-pattern where code might be using
@@ -521,6 +523,7 @@ export function dropManualMemoization(
521523 fnPlace ,
522524 func . env ,
523525 depsList ,
526+ depsLoc ,
524527 memoDecl ,
525528 nextManualMemoId ++ ,
526529 ) ;
0 commit comments