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

Function backpropAcrossTypeSwitch

assertion/function/assertiontree/backprop.go:536–586  ·  view source on GitHub ↗

backpropAcrossTypeSwitch handles type switches (e.g., "switch v := a.(*type)"), it is designed to be called from backpropAcrossAssignment as a finer-grained handler for special assignment cases. The main reason that this case has to be handled separately is that it introduces a "symbolic" variable t

(rootNode *RootAssertionNode, lhs *ast.Ident, rhs ast.Expr)

Source from the content-addressed store, hash-verified

534// without being able to compare the identity of `types.Var` instances as we usually do.
535// nonnil(lhs, rhs)
536func backpropAcrossTypeSwitch(rootNode *RootAssertionNode, lhs *ast.Ident, rhs ast.Expr) error {
537 // First, make a copy of the children array to iterate over, as we will mutate it.
538 children := slices.Clone(rootNode.Children())
539
540 // For each variable in the assertion tree, check if it's equal to the symbolic variable
541 // being instantiated by this type switch, and, if so, assign to it.
542 // we (annonyingly) have to handle this as a separate case and continue after the first child
543 // is found because there is no canonical instance of types.Object for symbolic type switch
544 // variables
545 for _, child := range children {
546 if varChild, ok := child.(*varAssertionNode); ok {
547 if varChild.decl.Pos() == lhs.Pos() &&
548 varChild.decl.Name() == lhs.Name {
549 // even though we can't do the matching through a types.Object instance, we conclude
550 // that the *types.Var in the assertion nodes matches the lhs of this assignment
551
552 liftedChild, _ := rootNode.LiftFromPath([]AssertionNode{varChild})
553 if liftedChild == nil {
554 // this nil check reflects programmer logic
555 return errors.New("liftedChild variable is nil")
556 }
557 rhsPath, rhsProducers := rootNode.ParseExprAsProducer(rhs, false)
558 if rhsPath != nil {
559 // rhs is trackable, so move assertions as we would in the vanilla assignment case
560 rootNode.LandAtPath(rhsPath, liftedChild)
561 // assignment complete
562 } else {
563 liftedChild.SetParent(rootNode)
564 switch len(rhsProducers) {
565 case 0:
566 // lhsVal expression will never be nil here because rhsVal will never be nil
567 rootNode.triggerProductions(liftedChild, &annotation.ProduceTrigger{
568 Annotation: &annotation.ProduceTriggerNever{},
569 Expr: lhs,
570 })
571 case 1:
572 rootNode.triggerProductions(liftedChild, &annotation.ProduceTrigger{
573 Annotation: rhsProducers[0].GetShallow().Annotation,
574 Expr: lhs,
575 }, rhsProducers[0].GetDeepSlice()...)
576 default:
577 return errors.New("expression e in a e.(type) switch was multiply returning - " +
578 "this should be a type error")
579 }
580 }
581 }
582 }
583 }
584 // no current assertion matches the type switch lhs variable here, so it's a no-op
585 return nil
586}
587
588// backpropAcrossOneToOneAssignment handles normal one-to-one assignment (e.g, "var a *int = b", or
589// "var a, b, c *int = d, e, f"), it is designed to be called from backpropAcrossAssignment as a

Callers 1

backpropAcrossAssignmentFunction · 0.85

Calls 9

LiftFromPathMethod · 0.80
ParseExprAsProducerMethod · 0.80
LandAtPathMethod · 0.80
triggerProductionsMethod · 0.80
ChildrenMethod · 0.65
SetParentMethod · 0.65
GetShallowMethod · 0.65
GetDeepSliceMethod · 0.65
PosMethod · 0.45

Tested by

no test coverage detected