// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// embedded types

package decls3

import "unsafe"
//import "fmt"
import "./time"

// fields with the same name at the same level cancel each other out

func _() {
	type (
		T1 struct { X int }
		T2 struct { X int }
		T3 struct { T1; T2 } // X is embedded twice at the same level via T1->X, T2->X
	)

	var t T3
	_ = t.X /* ERROR "ambiguous selector" */
}

func _() {
	type (
		T1 struct { X int }
		T2 struct { T1 }
		T3 struct { T1 }
		T4 struct { T2; T3 } // X is embedded twice at the same level via T2->T1->X, T3->T1->X
	)

	var t T4
	_ = t.X /* ERROR "ambiguous selector" */
}

func issue4355() {
	type (
	    T1 struct {X int}
	    T2 struct {T1}
	    T3 struct {T2}
	    T4 struct {T2}
	    T5 struct {T3; T4} // X is embedded twice at the same level via T3->T2->T1->X, T4->T2->T1->X
	)

	var t T5
	_ = t.X /* ERROR "ambiguous selector" */
}

func _() {
	type Time int
	type A struct{ Time }
	type B struct{ time.Time }
	type T struct{ A; B }

	var t T
	_ = t.Time /* ERROR "ambiguous selector" */
}

// Embedded fields can be predeclared types.

func _() {
	type T0 struct{
		int
		float32
		f int
	}
	var x T0
	_ = x.int
	_ = x.float32
	_ = x.f

	type T1 struct{
		T0
	}
	var y T1
	_ = y.int
	_ = y.float32
	_ = y.f
}

// Restrictions on embedded field types.

func _() {
	type I1 interface{}
	type I2 interface{}
	type P1 *int
	type P2 *int
	type UP unsafe.Pointer

	type T1 struct {
		I1
		* /* ERROR "cannot be a pointer to an interface" */ I2
		* /* ERROR "cannot be a pointer to an interface" */ error
		P1 /* ERROR "cannot be a pointer" */
		* /* ERROR "cannot be a pointer" */ P2
	}

	// unsafe.Pointers are treated like regular pointers when embedded
	type T2 struct {
		unsafe /* ERROR "cannot be unsafe.Pointer" */ .Pointer
		*/* ERROR "cannot be unsafe.Pointer" */ /* ERROR "Pointer redeclared" */ unsafe.Pointer
		UP /* ERROR "cannot be unsafe.Pointer" */
		* /* ERROR "cannot be unsafe.Pointer" */  /* ERROR "UP redeclared" */ UP
	}
}

// Named types that are pointers.

type S struct{ x int }
func (*S) m() {}
type P *S

func _() {
	var s *S
	_ = s.x
	_ = s.m

	var p P
	_ = p.x
	_ = p.m /* ERROR "no field or method" */
	_ = P.m /* ERROR "no field or method" */
}

// Borrowed from the FieldByName test cases in reflect/all_test.go.

type D1 struct {
	d int
}
type D2 struct {
	d int
}

type S0 struct {
	A, B, C int
	D1
	D2
}

type S1 struct {
	B int
	S0
}

type S2 struct {
	A int
	*S1
}

type S1x struct {
	S1
}

type S1y struct {
	S1
}

type S3 struct {
	S1x
	S2
	D, E int
	*S1y
}

type S4 struct {
	*S4
	A int
}

// The X in S6 and S7 annihilate, but they also block the X in S8.S9.
type S5 struct {
	S6
	S7
	S8
}

type S6 struct {
	X int
}

type S7 S6

type S8 struct {
	S9
}

type S9 struct {
	X int
	Y int
}

// The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9.
type S10 struct {
	S11
	S12
	S13
}

type S11 struct {
	S6
}

type S12 struct {
	S6
}

type S13 struct {
	S8
}

func _() {
	_ = struct{}{}.Foo /* ERROR "no field or method" */
	_ = S0{}.A
	_ = S0{}.D /* ERROR "no field or method" */
	_ = S1{}.A
	_ = S1{}.B
	_ = S1{}.S0
	_ = S1{}.C
	_ = S2{}.A
	_ = S2{}.S1
	_ = S2{}.B
	_ = S2{}.C
	_ = S2{}.D /* ERROR "no field or method" */
	_ = S3{}.S1 /* ERROR "ambiguous selector" */
	_ = S3{}.A
	_ = S3{}.B /* ERROR "ambiguous selector" */
	_ = S3{}.D
	_ = S3{}.E
	_ = S4{}.A
	_ = S4{}.B /* ERROR "no field or method" */
	_ = S5{}.X /* ERROR "ambiguous selector" */
	_ = S5{}.Y
	_ = S10{}.X /* ERROR "ambiguous selector" */
	_ = S10{}.Y
}

// Borrowed from the FieldByName benchmark in reflect/all_test.go.

type R0 struct {
	*R1
	*R2
	*R3
	*R4
}

type R1 struct {
	*R5
	*R6
	*R7
	*R8
}

type R2 R1
type R3 R1
type R4 R1

type R5 struct {
	*R9
	*R10
	*R11
	*R12
}

type R6 R5
type R7 R5
type R8 R5

type R9 struct {
	*R13
	*R14
	*R15
	*R16
}

type R10 R9
type R11 R9
type R12 R9

type R13 struct {
	*R17
	*R18
	*R19
	*R20
}

type R14 R13
type R15 R13
type R16 R13

type R17 struct {
	*R21
	*R22
	*R23
	*R24
}

type R18 R17
type R19 R17
type R20 R17

type R21 struct {
	X int
}

type R22 R21
type R23 R21
type R24 R21

var _ = R0{}.X /* ERROR "ambiguous selector" */