@@ -161,8 +161,8 @@ func analyzeControlFlow(r *analyzer.AnalyzerNode, block *ast.Block, cm *modules.
161161 hasConditionals := false
162162
163163 // Process all nodes in the block
164- earlyReturn , hasConditionals := processBlockNodes (r , block , cm , expectedReturnType , & result , & conditionalResults , hasConditionals )
165- if earlyReturn {
164+ foundReturn , hasConditionals := processBlockNodes (r , block , cm , expectedReturnType , & result , & conditionalResults , hasConditionals )
165+ if foundReturn {
166166 return result
167167 }
168168
@@ -179,15 +179,20 @@ func createEmptyControlFlowResult() ControlFlowResult {
179179 }
180180}
181181
182- // processBlockNodes processes all nodes in a block and returns early if return found
182+ // processBlockNodes processes all nodes in a block and detects unreachable code
183183func processBlockNodes (r * analyzer.AnalyzerNode , block * ast.Block , cm * modules.Module , expectedReturnType stype.Type ,
184184 result * ControlFlowResult , conditionalResults * []ControlFlowResult , hasConditionals bool ) (bool , bool ) {
185185
186186 reachable := true
187+ foundReturn := false
188+ var unreachableStart * source.Location
187189
188190 for _ , node := range block .Nodes {
189191 if ! reachable {
190- reportUnreachableCode (r , node )
192+ // Mark the start of unreachable section on first unreachable node
193+ if unreachableStart == nil {
194+ unreachableStart = node .Loc ()
195+ }
191196 continue
192197 }
193198
@@ -198,28 +203,35 @@ func processBlockNodes(r *analyzer.AnalyzerNode, block *ast.Block, cm *modules.M
198203 if ! hasConditionals {
199204 result .HasFallbackReturn = true
200205 }
201- return true , hasConditionals // Early return found
206+ reachable = false // Mark subsequent code as unreachable
207+ foundReturn = true
202208 case * ast.IfStmt :
203209 hasConditionals = true
204210 ifResult := analyzeIfStatement (r , n , cm , expectedReturnType )
205211 * conditionalResults = append (* conditionalResults , ifResult )
206212 if ifResult .AllPathsReturn {
207213 result .AllPathsReturn = true
208- return true , hasConditionals // All paths in if statement return
214+ reachable = false // Mark subsequent code as unreachable
215+ foundReturn = true
209216 }
210217 default :
211218 checkNode (r , node , cm )
212219 }
213220 }
214221
215- return false , hasConditionals
222+ // Report unreachable section once if any was found
223+ if unreachableStart != nil {
224+ reportUnreachableSection (r , unreachableStart )
225+ }
226+
227+ return foundReturn , hasConditionals
216228}
217229
218- // reportUnreachableCode reports unreachable code after return
219- func reportUnreachableCode (r * analyzer.AnalyzerNode , node ast. Node ) {
230+ // reportUnreachableSection reports a section of unreachable code after return
231+ func reportUnreachableSection (r * analyzer.AnalyzerNode , startLoc * source. Location ) {
220232 r .Ctx .Reports .AddSemanticError (
221233 r .Program .FullPath ,
222- node . Loc () ,
234+ startLoc ,
223235 "unreachable code after return statement" ,
224236 report .TYPECHECK_PHASE ,
225237 )
0 commit comments