learnNilness learns nilness for the block succ, extended from one nilnessTable table of its predecessor pred. The function creates a new nilnessTable that stores **only newly learned** nilness for succ block and a bool flag that indicates whether a conflict is seen when going to succ block from pred
(succ *ssa.BasicBlock, pred *ssa.BasicBlock, table nilnessTable)
| 158 | // not learn nilness for al kinds of conditions. For now we support only what is supported in |
| 159 | // the function branch. |
| 160 | func learnNilness(succ *ssa.BasicBlock, pred *ssa.BasicBlock, table nilnessTable) (nilnessTable, bool) { |
| 161 | lTable := nilnessTable{} // learned nilnessTable |
| 162 | eqSucc, neSucc, binOp := branch(pred) |
| 163 | // TODO: for now we learn nilness from only these two condition: ? == ? and ? != ? |
| 164 | if binOp == nil || eqSucc == nil || neSucc == nil { |
| 165 | // TODO: only binOp == nil is sufficient, but nilaway would not be happy with it. |
| 166 | return lTable, true |
| 167 | } |
| 168 | // TODO: each successor should learn a different nilness in terms of the variable |
| 169 | // involved in the condition. |
| 170 | xnil := table.nilnessOf(binOp.X) |
| 171 | ynil := table.nilnessOf(binOp.Y) |
| 172 | |
| 173 | // Both operands are known of nilness. |
| 174 | // Determine whether the branch is reachable. |
| 175 | if xnil != unknown && ynil != unknown { |
| 176 | if (xnil == ynil && succ == eqSucc) || (xnil != ynil && succ == neSucc) { |
| 177 | return lTable, true |
| 178 | } |
| 179 | // conflict |
| 180 | return lTable, false |
| 181 | } |
| 182 | |
| 183 | // Only one operand is known of nilness. |
| 184 | if ynil == unknown { |
| 185 | // learn the nilness of Y |
| 186 | if succ == eqSucc { |
| 187 | lTable.expandNilness(binOp.Y, xnil) |
| 188 | } else { |
| 189 | lTable.expandNilness(binOp.Y, xnil.negate()) |
| 190 | } |
| 191 | } else { |
| 192 | // learn the nilness of X |
| 193 | if succ == eqSucc { |
| 194 | lTable.expandNilness(binOp.X, ynil) |
| 195 | } else { |
| 196 | lTable.expandNilness(binOp.X, ynil.negate()) |
| 197 | } |
| 198 | } |
| 199 | return lTable, true |
| 200 | } |
| 201 | |
| 202 | // deriveContracts checks nilness of parameter and return values at every exit block to infer |
| 203 | // contracts. |
no test coverage detected