mirror of
https://github.com/golang/go
synced 2024-11-18 18:54:42 -07:00
go.tools/go/types: treat unsafe.Pointer like a pointer for receivers and embedding
Also: Better error message for receiver type errors. R=adonovan CC=golang-dev https://golang.org/cl/13259044
This commit is contained in:
parent
67c866ec74
commit
3fee9166d4
10
go/types/testdata/decls2a.src
vendored
10
go/types/testdata/decls2a.src
vendored
@ -27,10 +27,10 @@ type T1b struct {
|
||||
func (T1b) int /* ERROR "field and method" */ () {}
|
||||
|
||||
type T1c struct {
|
||||
unsafe.Pointer
|
||||
time.Time
|
||||
}
|
||||
|
||||
func (T1c) Pointer /* ERROR "field and method" */ () int { return 0 }
|
||||
func (T1c) Time /* ERROR "field and method" */ () int { return 0 }
|
||||
|
||||
// Disabled for now: LookupFieldOrMethod will find Pointer even though
|
||||
// it's double-declared (it would cost extra in the common case to verify
|
||||
@ -84,8 +84,14 @@ func (T5 /* ERROR "invalid receiver" */ ) m2() {}
|
||||
func (int /* ERROR "invalid receiver" */ ) m() {}
|
||||
func ([ /* ERROR "identifier" */ ]int) m() {}
|
||||
func (time /* ERROR "identifier" */ .Time) m() {}
|
||||
func (*time /* ERROR "identifier" */ .Time) m() {}
|
||||
func (x interface /* ERROR "identifier" */ {}) m() {}
|
||||
|
||||
// Unsafe.Pointer is treated like a pointer when used as receiver type.
|
||||
type UP unsafe.Pointer
|
||||
func (UP /* ERROR "invalid" */ ) m1() {}
|
||||
func (* /* ERROR "invalid" */ UP) m2() {}
|
||||
|
||||
// Double declarations across package files
|
||||
const c_double = 0
|
||||
type t_double int
|
||||
|
21
go/types/testdata/decls3.src
vendored
21
go/types/testdata/decls3.src
vendored
@ -7,6 +7,7 @@
|
||||
package decls3
|
||||
|
||||
import "unsafe"
|
||||
import "fmt"
|
||||
|
||||
// fields with the same name at the same level cancel each other out
|
||||
|
||||
@ -47,13 +48,13 @@ func issue4355() {
|
||||
}
|
||||
|
||||
func _() {
|
||||
type Pointer int
|
||||
type A struct{ Pointer }
|
||||
type B struct{ unsafe.Pointer }
|
||||
type State int
|
||||
type A struct{ State }
|
||||
type B struct{ fmt.State }
|
||||
type T struct{ A; B }
|
||||
|
||||
var t T
|
||||
_ = t /* ERROR "ambiguous selector" */ .Pointer
|
||||
_ = t /* ERROR "ambiguous selector" */ .State
|
||||
}
|
||||
|
||||
// Embedded fields can be predeclared types.
|
||||
@ -85,6 +86,7 @@ func _() {
|
||||
type I2 interface{}
|
||||
type P1 *int
|
||||
type P2 *int
|
||||
type UP unsafe.Pointer
|
||||
|
||||
type T1 struct {
|
||||
I1
|
||||
@ -94,13 +96,12 @@ func _() {
|
||||
* /* ERROR "cannot be a pointer" */ P2
|
||||
}
|
||||
|
||||
// unsafe.Pointers are not regular pointers
|
||||
// unsafe.Pointers are treated like regular pointers when embedded
|
||||
type T2 struct {
|
||||
unsafe.Pointer
|
||||
}
|
||||
|
||||
type T3 struct {
|
||||
*unsafe.Pointer
|
||||
unsafe /* ERROR "cannot be unsafe.Pointer" */ .Pointer
|
||||
*/* ERROR "cannot be unsafe.Pointer" */ unsafe.Pointer
|
||||
UP /* ERROR "cannot be unsafe.Pointer" */
|
||||
* /* ERROR "cannot be unsafe.Pointer" */ UP
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,24 +140,29 @@ func (check *checker) funcType(recv *ast.FieldList, ftyp *ast.FuncType, def *Nam
|
||||
// spec: "The receiver type must be of the form T or *T where T is a type name."
|
||||
// (ignore invalid types - error was reported before)
|
||||
if t, _ := deref(recv.typ); t != Typ[Invalid] {
|
||||
ok := true
|
||||
var err string
|
||||
if T, _ := t.(*Named); T != nil {
|
||||
// spec: "The type denoted by T is called the receiver base type; it must not
|
||||
// be a pointer or interface type and it must be declared in the same package
|
||||
// as the method."
|
||||
switch T.underlying.(type) {
|
||||
case *Pointer, *Interface:
|
||||
ok = false
|
||||
}
|
||||
if T.obj.pkg != check.pkg {
|
||||
ok = false
|
||||
err = "type not defined in this package"
|
||||
} else {
|
||||
switch u := T.underlying.(type) {
|
||||
case *Basic:
|
||||
// unsafe.Pointer is treated like a regular pointer
|
||||
if u.kind == UnsafePointer {
|
||||
err = "unsafe.Pointer"
|
||||
}
|
||||
case *Pointer, *Interface:
|
||||
err = "pointer or interface type"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ok = false
|
||||
err = "basic or unnamed type"
|
||||
}
|
||||
if !ok {
|
||||
// TODO(gri) provide better error message depending on error
|
||||
check.errorf(recv.pos, "invalid receiver %s", recv)
|
||||
if err != "" {
|
||||
check.errorf(recv.pos, "invalid receiver %s (%s)", recv.typ, err)
|
||||
// ok to continue
|
||||
}
|
||||
}
|
||||
@ -489,24 +494,38 @@ func (check *checker) collectFields(list *ast.FieldList, cycleOk bool) (fields [
|
||||
switch t := t.(type) {
|
||||
case *Basic:
|
||||
if t == Typ[Invalid] {
|
||||
continue // ignore this field - error was reported before
|
||||
// error was reported before
|
||||
continue
|
||||
}
|
||||
// unsafe.Pointer is treated like a regular pointer
|
||||
if t.kind == UnsafePointer {
|
||||
check.errorf(pos, "anonymous field type cannot be unsafe.Pointer")
|
||||
continue
|
||||
}
|
||||
add(f, nil, t.name, true, pos)
|
||||
|
||||
case *Named:
|
||||
// spec: "An embedded type must be specified as a type name
|
||||
// T or as a pointer to a non-interface type name *T, and T
|
||||
// itself may not be a pointer type."
|
||||
switch t.Underlying().(type) {
|
||||
switch u := t.Underlying().(type) {
|
||||
case *Basic:
|
||||
// unsafe.Pointer is treated like a regular pointer
|
||||
if u.kind == UnsafePointer {
|
||||
check.errorf(pos, "anonymous field type cannot be unsafe.Pointer")
|
||||
continue
|
||||
}
|
||||
case *Pointer:
|
||||
check.errorf(pos, "anonymous field type cannot be a pointer")
|
||||
continue // ignore this field
|
||||
continue
|
||||
case *Interface:
|
||||
if isPtr {
|
||||
check.errorf(pos, "anonymous field type cannot be a pointer to an interface")
|
||||
continue // ignore this field
|
||||
continue
|
||||
}
|
||||
}
|
||||
add(f, nil, t.obj.name, true, pos)
|
||||
|
||||
default:
|
||||
check.invalidAST(pos, "anonymous field type %s must be named", typ)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user