MCPcopy
hub / github.com/uber-go/nilaway / backpropAcrossRange

Function backpropAcrossRange

assertion/function/assertiontree/backprop.go:414–524  ·  view source on GitHub ↗

backpropAcrossRange handles range expression (e.g., "for i, v := range lst"), it is designed to be called from backpropAcrossAssignment as a finer-grained handler for special assignment cases.

(rootNode *RootAssertionNode, lhs []ast.Expr, rhs ast.Expr)

Source from the content-addressed store, hash-verified

412// backpropAcrossRange handles range expression (e.g., "for i, v := range lst"), it is designed to
413// be called from backpropAcrossAssignment as a finer-grained handler for special assignment cases.
414func backpropAcrossRange(rootNode *RootAssertionNode, lhs []ast.Expr, rhs ast.Expr) error {
415 // produceAsIndex(i) marks the ith lhs expression as a range index, producing it as non-nil
416 // because it necessarily has basic type (int or char)
417 produceAsIndex := func(i int) {
418 // if nonempty, produce the index as definitely non-nil
419 if !asthelper.IsEmptyExpr(lhs[i]) {
420 rootNode.AddProduction(&annotation.ProduceTrigger{
421 Annotation: &annotation.RangeIndexAssignment{ProduceTriggerNever: &annotation.ProduceTriggerNever{}},
422 Expr: lhs[i],
423 })
424 }
425 }
426
427 // produceAsDeepRHS(i) marks the ith lhs expression as flowing deeply from the rhs
428 produceAsDeepRHS := func(i int) {
429 // if nonempty, produce the ranging value from the deep nilability of the rhs
430 // we can't track the rhs of ranges since we would need to discover non-nil assignments
431 // to an unbounded number of indices to conclude anything other than the annotation-based
432 // deep nilability of rhs
433 if !asthelper.IsEmptyExpr(lhs[i]) {
434 producer := exprAsDeepProducer(rootNode, rhs)
435 producer.SetNeedsGuard(false)
436
437 rootNode.AddProduction(&annotation.ProduceTrigger{
438 // we remove the guard on any deep types read from a range because reading
439 // them through a range guarantees they exist, removing the need for an ok check
440 Annotation: producer,
441 Expr: lhs[i],
442 })
443 }
444 }
445
446 // produceNonNil marks the ith lhs expression as nonnil due to limitations of NilAway.
447 produceNonNil := func(i int) {
448 if !asthelper.IsEmptyExpr(lhs[i]) {
449 rootNode.AddProduction(&annotation.ProduceTrigger{
450 Annotation: &annotation.ProduceTriggerNever{},
451 Expr: lhs[i],
452 })
453 }
454 }
455
456 rhsType := types.Unalias(rootNode.Pass().TypesInfo.Types[rhs].Type)
457
458 // Go 1.23 introduced [range-over-func] language feature, where the `range` statement can
459 // now take the following types:
460 //
461 // 1. `func(func() bool)`
462 // 2. `func(func(K) bool)`
463 // 3. `func(func(K, V) bool)`
464 //
465 // We currently do not handle these types yet, so here we assume that they are deeply non-nil
466 // (by adding nonnil producers to both K and V if given).
467 //
468 // Note that the `iter` package provides `iter.Seq` and `iter.Seq2` generic types for 2 and 3
469 // specifically. Therefore, we need to `.Underlying()` on the rhsType to find the underlying
470 // func type for simplicity.
471 //

Callers 1

backpropAcrossAssignmentFunction · 0.85

Calls 9

IsEmptyExprFunction · 0.92
IsIterTypeFunction · 0.92
IsDeeplyArrayOrArrayPtrFunction · 0.92
exprAsDeepProducerFunction · 0.85
typeIsStringFunction · 0.85
AddProductionMethod · 0.80
PassMethod · 0.80
SetNeedsGuardMethod · 0.65
ErrorfMethod · 0.65

Tested by

no test coverage detected