Source file src/cmd/compile/internal/types2/builtins_test.go

     1  // Copyright 2013 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package types2_test
     6  
     7  import (
     8  	"cmd/compile/internal/syntax"
     9  	"fmt"
    10  	"strings"
    11  	"testing"
    12  
    13  	. "cmd/compile/internal/types2"
    14  )
    15  
    16  var builtinCalls = []struct {
    17  	name, src, sig string
    18  }{
    19  	{"append", `var s []int; _ = append(s)`, `func([]int, ...int) []int`},
    20  	{"append", `var s []int; _ = append(s, 0)`, `func([]int, ...int) []int`},
    21  	{"append", `var s []int; _ = (append)(s, 0)`, `func([]int, ...int) []int`},
    22  	{"append", `var s []byte; _ = ((append))(s, 0)`, `func([]byte, ...byte) []byte`},
    23  	{"append", `var s []byte; _ = append(s, "foo"...)`, `func([]byte, string...) []byte`},
    24  	{"append", `type T []byte; var s T; var str string; _ = append(s, str...)`, `func(p.T, string...) p.T`},
    25  	{"append", `type T []byte; type U string; var s T; var str U; _ = append(s, str...)`, `func(p.T, p.U...) p.T`},
    26  
    27  	{"cap", `var s [10]int; _ = cap(s)`, `invalid type`},  // constant
    28  	{"cap", `var s [10]int; _ = cap(&s)`, `invalid type`}, // constant
    29  	{"cap", `var s []int64; _ = cap(s)`, `func([]int64) int`},
    30  	{"cap", `var c chan<-bool; _ = cap(c)`, `func(chan<- bool) int`},
    31  	{"cap", `type S []byte; var s S; _ = cap(s)`, `func(p.S) int`},
    32  	{"cap", `var s P; _ = cap(s)`, `func(P) int`},
    33  
    34  	{"len", `_ = len("foo")`, `invalid type`}, // constant
    35  	{"len", `var s string; _ = len(s)`, `func(string) int`},
    36  	{"len", `var s [10]int; _ = len(s)`, `invalid type`},  // constant
    37  	{"len", `var s [10]int; _ = len(&s)`, `invalid type`}, // constant
    38  	{"len", `var s []int64; _ = len(s)`, `func([]int64) int`},
    39  	{"len", `var c chan<-bool; _ = len(c)`, `func(chan<- bool) int`},
    40  	{"len", `var m map[string]float32; _ = len(m)`, `func(map[string]float32) int`},
    41  	{"len", `type S []byte; var s S; _ = len(s)`, `func(p.S) int`},
    42  	{"len", `var s P; _ = len(s)`, `func(P) int`},
    43  
    44  	{"close", `var c chan int; close(c)`, `func(chan int)`},
    45  	{"close", `var c chan<- chan string; close(c)`, `func(chan<- chan string)`},
    46  
    47  	{"complex", `_ = complex(1, 0)`, `invalid type`}, // constant
    48  	{"complex", `var re float32; _ = complex(re, 1.0)`, `func(float32, float32) complex64`},
    49  	{"complex", `var im float64; _ = complex(1, im)`, `func(float64, float64) complex128`},
    50  	{"complex", `type F32 float32; var re, im F32; _ = complex(re, im)`, `func(p.F32, p.F32) complex64`},
    51  	{"complex", `type F64 float64; var re, im F64; _ = complex(re, im)`, `func(p.F64, p.F64) complex128`},
    52  
    53  	{"copy", `var src, dst []byte; copy(dst, src)`, `func([]byte, []byte) int`},
    54  	{"copy", `type T [][]int; var src, dst T; _ = copy(dst, src)`, `func(p.T, p.T) int`},
    55  	{"copy", `var src string; var dst []byte; copy(dst, src)`, `func([]byte, string) int`},
    56  	{"copy", `type T string; type U []byte; var src T; var dst U; copy(dst, src)`, `func(p.U, p.T) int`},
    57  	{"copy", `var dst []byte; copy(dst, "hello")`, `func([]byte, string) int`},
    58  
    59  	{"delete", `var m map[string]bool; delete(m, "foo")`, `func(map[string]bool, string)`},
    60  	{"delete", `type (K string; V int); var m map[K]V; delete(m, "foo")`, `func(map[p.K]p.V, p.K)`},
    61  
    62  	{"imag", `_ = imag(1i)`, `invalid type`}, // constant
    63  	{"imag", `var c complex64; _ = imag(c)`, `func(complex64) float32`},
    64  	{"imag", `var c complex128; _ = imag(c)`, `func(complex128) float64`},
    65  	{"imag", `type C64 complex64; var c C64; _ = imag(c)`, `func(p.C64) float32`},
    66  	{"imag", `type C128 complex128; var c C128; _ = imag(c)`, `func(p.C128) float64`},
    67  
    68  	{"real", `_ = real(1i)`, `invalid type`}, // constant
    69  	{"real", `var c complex64; _ = real(c)`, `func(complex64) float32`},
    70  	{"real", `var c complex128; _ = real(c)`, `func(complex128) float64`},
    71  	{"real", `type C64 complex64; var c C64; _ = real(c)`, `func(p.C64) float32`},
    72  	{"real", `type C128 complex128; var c C128; _ = real(c)`, `func(p.C128) float64`},
    73  
    74  	{"make", `_ = make([]int, 10)`, `func([]int, int) []int`},
    75  	{"make", `type T []byte; _ = make(T, 10, 20)`, `func(p.T, int, int) p.T`},
    76  
    77  	// issue #37349
    78  	{"make", `              _ = make([]int, 0   )`, `func([]int, int) []int`},
    79  	{"make", `var l    int; _ = make([]int, l   )`, `func([]int, int) []int`},
    80  	{"make", `              _ = make([]int, 0, 0)`, `func([]int, int, int) []int`},
    81  	{"make", `var l    int; _ = make([]int, l, 0)`, `func([]int, int, int) []int`},
    82  	{"make", `var    c int; _ = make([]int, 0, c)`, `func([]int, int, int) []int`},
    83  	{"make", `var l, c int; _ = make([]int, l, c)`, `func([]int, int, int) []int`},
    84  
    85  	// issue #37393
    86  	{"make", `                _ = make([]int       , 0   )`, `func([]int, int) []int`},
    87  	{"make", `var l    byte ; _ = make([]int8      , l   )`, `func([]int8, byte) []int8`},
    88  	{"make", `                _ = make([]int16     , 0, 0)`, `func([]int16, int, int) []int16`},
    89  	{"make", `var l    int16; _ = make([]string    , l, 0)`, `func([]string, int16, int) []string`},
    90  	{"make", `var    c int32; _ = make([]float64   , 0, c)`, `func([]float64, int, int32) []float64`},
    91  	{"make", `var l, c uint ; _ = make([]complex128, l, c)`, `func([]complex128, uint, uint) []complex128`},
    92  
    93  	// issue #45667
    94  	{"make", `const l uint = 1; _ = make([]int, l)`, `func([]int, uint) []int`},
    95  
    96  	{"new", `_ = new(int)`, `func(int) *int`},
    97  	{"new", `type T struct{}; _ = new(T)`, `func(p.T) *p.T`},
    98  
    99  	{"panic", `panic(0)`, `func(interface{})`},
   100  	{"panic", `panic("foo")`, `func(interface{})`},
   101  
   102  	{"print", `print()`, `func()`},
   103  	{"print", `print(0)`, `func(int)`},
   104  	{"print", `print(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`},
   105  
   106  	{"println", `println()`, `func()`},
   107  	{"println", `println(0)`, `func(int)`},
   108  	{"println", `println(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`},
   109  
   110  	{"recover", `recover()`, `func() interface{}`},
   111  	{"recover", `_ = recover()`, `func() interface{}`},
   112  
   113  	{"Add", `var p unsafe.Pointer; _ = unsafe.Add(p, -1.0)`, `func(unsafe.Pointer, int) unsafe.Pointer`},
   114  	{"Add", `var p unsafe.Pointer; var n uintptr; _ = unsafe.Add(p, n)`, `func(unsafe.Pointer, uintptr) unsafe.Pointer`},
   115  	{"Add", `_ = unsafe.Add(nil, 0)`, `func(unsafe.Pointer, int) unsafe.Pointer`},
   116  
   117  	{"Alignof", `_ = unsafe.Alignof(0)`, `invalid type`},                 // constant
   118  	{"Alignof", `var x struct{}; _ = unsafe.Alignof(x)`, `invalid type`}, // constant
   119  	{"Alignof", `var x P; _ = unsafe.Alignof(x)`, `func(P) uintptr`},
   120  
   121  	{"Offsetof", `var x struct{f bool}; _ = unsafe.Offsetof(x.f)`, `invalid type`},           // constant
   122  	{"Offsetof", `var x struct{_ int; f bool}; _ = unsafe.Offsetof((&x).f)`, `invalid type`}, // constant
   123  	{"Offsetof", `var x struct{_ int; f P}; _ = unsafe.Offsetof((&x).f)`, `func(P) uintptr`},
   124  
   125  	{"Sizeof", `_ = unsafe.Sizeof(0)`, `invalid type`},                 // constant
   126  	{"Sizeof", `var x struct{}; _ = unsafe.Sizeof(x)`, `invalid type`}, // constant
   127  	{"Sizeof", `var x P; _ = unsafe.Sizeof(x)`, `func(P) uintptr`},
   128  
   129  	{"Slice", `var p *int; _ = unsafe.Slice(p, 1)`, `func(*int, int) []int`},
   130  	{"Slice", `var p *byte; var n uintptr; _ = unsafe.Slice(p, n)`, `func(*byte, uintptr) []byte`},
   131  
   132  	{"assert", `assert(true)`, `invalid type`},                                    // constant
   133  	{"assert", `type B bool; const pred B = 1 < 2; assert(pred)`, `invalid type`}, // constant
   134  
   135  	// no tests for trace since it produces output as a side-effect
   136  }
   137  
   138  func TestBuiltinSignatures(t *testing.T) {
   139  	DefPredeclaredTestFuncs()
   140  
   141  	seen := map[string]bool{"trace": true} // no test for trace built-in; add it manually
   142  	for _, call := range builtinCalls {
   143  		testBuiltinSignature(t, call.name, call.src, call.sig)
   144  		seen[call.name] = true
   145  	}
   146  
   147  	// make sure we didn't miss one
   148  	for _, name := range Universe.Names() {
   149  		if _, ok := Universe.Lookup(name).(*Builtin); ok && !seen[name] {
   150  			t.Errorf("missing test for %s", name)
   151  		}
   152  	}
   153  	for _, name := range Unsafe.Scope().Names() {
   154  		if _, ok := Unsafe.Scope().Lookup(name).(*Builtin); ok && !seen[name] {
   155  			t.Errorf("missing test for unsafe.%s", name)
   156  		}
   157  	}
   158  }
   159  
   160  func parseGenericSrc(path, src string) (*syntax.File, error) {
   161  	errh := func(error) {} // dummy error handler so that parsing continues in presence of errors
   162  	return syntax.Parse(syntax.NewFileBase(path), strings.NewReader(src), errh, nil, syntax.AllowGenerics)
   163  }
   164  
   165  func testBuiltinSignature(t *testing.T, name, src0, want string) {
   166  	src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _[P ~[]byte]() { %s }`, src0)
   167  	f, err := parseGenericSrc("", src)
   168  	if err != nil {
   169  		t.Errorf("%s: %s", src0, err)
   170  		return
   171  	}
   172  
   173  	conf := Config{Importer: defaultImporter()}
   174  	uses := make(map[*syntax.Name]Object)
   175  	types := make(map[syntax.Expr]TypeAndValue)
   176  	_, err = conf.Check(f.PkgName.Value, []*syntax.File{f}, &Info{Uses: uses, Types: types})
   177  	if err != nil {
   178  		t.Errorf("%s: %s", src0, err)
   179  		return
   180  	}
   181  
   182  	// find called function
   183  	n := 0
   184  	var fun syntax.Expr
   185  	for x := range types {
   186  		if call, _ := x.(*syntax.CallExpr); call != nil {
   187  			fun = call.Fun
   188  			n++
   189  		}
   190  	}
   191  	if n != 1 {
   192  		t.Errorf("%s: got %d CallExprs; want 1", src0, n)
   193  		return
   194  	}
   195  
   196  	// check recorded types for fun and descendents (may be parenthesized)
   197  	for {
   198  		// the recorded type for the built-in must match the wanted signature
   199  		typ := types[fun].Type
   200  		if typ == nil {
   201  			t.Errorf("%s: no type recorded for %s", src0, syntax.String(fun))
   202  			return
   203  		}
   204  		if got := typ.String(); got != want {
   205  			t.Errorf("%s: got type %s; want %s", src0, got, want)
   206  			return
   207  		}
   208  
   209  		// called function must be a (possibly parenthesized, qualified)
   210  		// identifier denoting the expected built-in
   211  		switch p := fun.(type) {
   212  		case *syntax.Name:
   213  			obj := uses[p]
   214  			if obj == nil {
   215  				t.Errorf("%s: no object found for %s", src0, p.Value)
   216  				return
   217  			}
   218  			bin, _ := obj.(*Builtin)
   219  			if bin == nil {
   220  				t.Errorf("%s: %s does not denote a built-in", src0, p.Value)
   221  				return
   222  			}
   223  			if bin.Name() != name {
   224  				t.Errorf("%s: got built-in %s; want %s", src0, bin.Name(), name)
   225  				return
   226  			}
   227  			return // we're done
   228  
   229  		case *syntax.ParenExpr:
   230  			fun = p.X // unpack
   231  
   232  		case *syntax.SelectorExpr:
   233  			// built-in from package unsafe - ignore details
   234  			return // we're done
   235  
   236  		default:
   237  			t.Errorf("%s: invalid function call", src0)
   238  			return
   239  		}
   240  	}
   241  }
   242  

View as plain text