type ConstCase … type TypeCase … type Switch … func (sw *Switch) String() string { … } // Switches examines the control-flow graph of fn and returns the // set of inferred value and type switches. A value switch tests an // ssa.Value for equality against two or more compile-time constant // values. Switches involving link-time constants (addresses) are // ignored. A type switch type-asserts an ssa.Value against two or // more types. // // The switches are returned in dominance order. // // The resulting switches do not necessarily correspond to uses of the // 'switch' keyword in the source: for example, a single source-level // switch statement with non-constant cases may result in zero, one or // many Switches, one per plural sequence of constant cases. // Switches may even be inferred from if/else- or goto-based control flow. // (In general, the control flow constructs of the source program // cannot be faithfully reproduced from the SSA representation.) func Switches(fn *ssa.Function) []Switch { … } func valueSwitch(sw *Switch, k *ssa.Const, seen map[*ssa.BasicBlock]bool) { … } func typeSwitch(sw *Switch, y ssa.Value, T types.Type, seen map[*ssa.BasicBlock]bool) { … } // isComparisonBlock returns the operands (v, k) if a block ends with // a comparison v==k, where k is a compile-time constant. func isComparisonBlock(b *ssa.BasicBlock) (v ssa.Value, k *ssa.Const) { … } // isTypeAssertBlock returns the operands (y, x, T) if a block ends with // a type assertion "if y, ok := x.(T); ok {". func isTypeAssertBlock(b *ssa.BasicBlock) (y, x ssa.Value, T types.Type) { … }