1
0
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:
Robert Griesemer 2013-09-11 10:03:40 -07:00
parent 67c866ec74
commit 3fee9166d4
3 changed files with 52 additions and 26 deletions

View File

@ -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

View File

@ -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
}
}

View File

@ -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)
}