private boolean inferTemplatedTypesForCall ( Node n , FunctionType fnType , FlowScope scope ) { ImmutableList < TemplateType > keys = fnType . getTemplateTypeMap ( ) . getTemplateKeys ( ) ; if ( keys . isEmpty ( ) ) { return false ; } // Try to infer the template types Map < TemplateType , JSType > rawInferrence = inferTemplateTypesFromParameters ( fnType , n , scope ) ; Map < TemplateType , JSType > inferred = Maps . newIdentityHashMap ( ) ; for ( TemplateType key : keys ) { JSType type = rawInferrence . get ( key ) ; if ( type == null ) { type = unknownType ; } inferred . put ( key , type ) ; } // Try to infer the template types using the type transformations Map < TemplateType , JSType > typeTransformations = evaluateTypeTransformations ( keys , inferred , scope ) ; if ( typeTransformations != null ) { inferred . putAll ( typeTransformations ) ; } // Replace all template types. If we couldn't find a replacement, we // replace it with UNKNOWN. TemplateTypeReplacer replacer = new TemplateTypeReplacer ( registry , inferred ) ; Node callTarget = n . getFirstChild ( ) ; FunctionType replacementFnType = fnType . visit ( replacer ) . toMaybeFunctionType ( ) ; checkNotNull ( replacementFnType ) ; callTarget . setJSType ( replacementFnType ) ; n . setJSType ( replacementFnType . getReturnType ( ) ) ; return replacer . madeChanges ; }
For functions that use template types specialize the function type for the call target based on the call - site specific arguments . Specifically this enables inference to set the type of any function literal parameters based on these inferred types .