package main

// This file is the input to TestValueForExpr in source_test.go, which
// ensures that each expression e immediately following a /*@kind*/(x)
// annotation, when passed to Function.ValueForExpr(e), returns a
// non-nil Value of the same type as e and of kind 'kind'.

func f(spilled, unspilled int) {
	_ = /*@Parameter*/ (spilled)
	_ = /*@Parameter*/ (unspilled)
	_ = /*@nil*/ (1 + 2) // (constant)
	i := 0

	f := func() (int, int) { return 0, 0 }

	/*@Call*/
	(print( /*@BinOp*/ (i + 1)))
	_, _ = /*@Call*/ (f())
	ch := /*@MakeChan*/ (make(chan int))
	/*@Recv*/ (<-ch)
	x := /*@Recv*/ (<-ch)
	_ = x
	select {
	case /*@Extract*/ (<-ch):
	case x := /*@Extract*/ (<-ch):
		_ = x
	}
	defer /*@Function*/ (func() {
	})()
	go /*@Function*/ (func() {
	})()
	y := 0
	if true && /*@BinOp*/ (bool(y > 0)) {
		y = 1
	}
	_ = /*@Phi*/ (y)
	map1 := /*@MakeMap*/ (make(map[string]string))
	_ = map1
	_ = /*@Slice*/ (make([]int, 0))
	_ = /*@MakeClosure*/ (func() { print(spilled) })

	_ = /*@Load*/ (spilled)

	sl := []int{}
	_ = /*@Slice*/ (sl[:0])

	_ = /*@Alloc*/ (new(int))
	tmp := /*@Alloc*/ (new(int))
	_ = tmp
	var iface interface{}
	_ = /*@TypeAssert*/ (iface.(int))
	_ = /*@Load*/ (sl[0])
	_ = /*@IndexAddr*/ (&sl[0])
	_ = /*@Index*/ ([2]int{}[0])
	var p *int
	_ = /*@Load*/ (*p)

	_ = /*@Load*/ (global)
	/*@Load*/ (global)[""] = ""
	/*@Global*/ (global) = map[string]string{}

	var local t
	/*UnOp*/ (local.x) = 1

	// Exercise corner-cases of lvalues vs rvalues.
	type N *N
	var n N
	/*@Const*/ (n) = /*@Const*/ (n)
	/*@ChangeType*/ (n) = /*@Alloc*/ (&n)
	/*@Load*/ (n) = /*@Load*/ n
	/*@Load*/ (n) = /*@Load*/ (*n)
	/*@Load*/ (n) = /*@Load*/ (**n)
}

func complit() {
	// Composite literals.
	// We get different results for
	// - composite literal as value (e.g. operand to print)
	// - composite literal initializer for addressable value
	// - composite literal value assigned to blank var

	// 1. Slices
	print( /*@Slice*/ ([]int{}))
	print( /*@Alloc*/ (&[]int{}))
	print(& /*@Slice*/ ([]int{}))

	sl1 := /*@Slice*/ ([]int{})
	sl2 := /*@Alloc*/ (&[]int{})
	sl3 := & /*@Slice*/ ([]int{})
	_, _, _ = sl1, sl2, sl3

	_ = /*@Slice*/ ([]int{})
	_ = /*@Alloc*/ (& /*@Slice*/ ([]int{}))
	_ = & /*@Slice*/ ([]int{})

	// 2. Arrays
	print( /*@Const*/ ([1]int{}))
	print( /*@Alloc*/ (&[1]int{}))
	print(& /*@Alloc*/ ([1]int{}))

	arr1 := /*@Const*/ ([1]int{})
	arr2 := /*@Alloc*/ (&[1]int{})
	arr3 := & /*@Alloc*/ ([1]int{})
	_, _, _ = arr1, arr2, arr3

	_ = /*@Const*/ ([1]int{})
	_ = /*@Alloc*/ (& /*@Alloc*/ ([1]int{}))
	_ = & /*@Alloc*/ ([1]int{})

	// 3. Maps
	type M map[int]int
	print( /*@MakeMap*/ (M{}))
	print( /*@Alloc*/ (&M{}))
	print(& /*@MakeMap*/ (M{}))

	m1 := /*@MakeMap*/ (M{})
	m2 := /*@Alloc*/ (&M{})
	m3 := & /*@MakeMap*/ (M{})
	_, _, _ = m1, m2, m3

	_ = /*@MakeMap*/ (M{})
	_ = /*@Alloc*/ (& /*@MakeMap*/ (M{}))
	_ = & /*@MakeMap*/ (M{})

	// 4. Structs
	print( /*@Const*/ (struct{}{}))
	print( /*@Alloc*/ (&struct{}{}))
	print(& /*@Alloc*/ (struct{}{}))

	s1 := /*@Const*/ (struct{}{})
	s2 := /*@Alloc*/ (&struct{}{})
	s3 := & /*@Alloc*/ (struct{}{})
	_, _, _ = s1, s2, s3

	_ = /*@Const*/ (struct{}{})
	_ = /*@Alloc*/ (& /*@Alloc*/ (struct{}{}))
	_ = & /*@Alloc*/ (struct{}{})
}

type t struct{ x int }

// Ensure we can locate methods of named types.
func (t) f(param int) {
	_ = /*@Parameter*/ (param)
}

// Ensure we can locate init functions.
func init() {
	m := /*@MakeMap*/ (make(map[string]string))
	_ = m
}

// Ensure we can locate variables in initializer expressions.
var global = /*@MakeMap*/ (make(map[string]string))

type t1 struct {
	x int
}
type t2 struct {
	x int `tag`
}

func main() {
	var tv1 t1
	var tv2 t2 = /*@ChangeType*/ (t2(tv1))
	_ = tv2
}
