type resultsAnalyzer … type resultVal … // addResultsAnalyzer creates a new resultsAnalyzer helper object for // the function fn, appends it to the analyzers list, and returns the // new list. If the function in question doesn't have any returns (or // any interesting returns) then the analyzer list is left as is, and // the result flags in "fp" are updated accordingly. func addResultsAnalyzer(fn *ir.Func, analyzers []propAnalyzer, fp *FuncProps, inlineMaxBudget int, nf *nameFinder) []propAnalyzer { … } // makeResultsAnalyzer creates a new helper object to analyze results // in function fn. If the function doesn't have any interesting // results, a nil helper is returned along with a set of default // result flags for the func. func makeResultsAnalyzer(fn *ir.Func, inlineMaxBudget int, nf *nameFinder) (*resultsAnalyzer, []ResultPropBits) { … } // setResults transfers the calculated result properties for this // function to 'funcProps'. func (ra *resultsAnalyzer) setResults(funcProps *FuncProps) { … } func (ra *resultsAnalyzer) pessimize() { … } func (ra *resultsAnalyzer) nodeVisitPre(n ir.Node) { … } func (ra *resultsAnalyzer) nodeVisitPost(n ir.Node) { … } // analyzeResult examines the expression 'n' being returned as the // 'ii'th argument in some return statement to see whether has // interesting characteristics (for example, returns a constant), then // applies a dataflow "meet" operation to combine this result with any // previous result (for the given return slot) that we've already // processed. func (ra *resultsAnalyzer) analyzeResult(ii int, n ir.Node) { … } // deriveReturnFlagsFromCallee tries to set properties for a given // return result where we're returning call expression; return value // is a return property value and a boolean indicating whether the // prop is valid. Examples: // // func foo() int { return bar() } // func bar() int { return 42 } // func blix() int { return 43 } // func two(y int) int { // if y < 0 { return bar() } else { return blix() } // } // // Since "foo" always returns the result of a call to "bar", we can // set foo's return property to that of bar. In the case of "two", however, // even though each return path returns a constant, we don't know // whether the constants are identical, hence we need to be conservative. func (ra *resultsAnalyzer) deriveReturnFlagsFromCallee(n ir.Node) (ResultPropBits, bool) { … }