Commit deefcb26 authored by Robert Griesemer's avatar Robert Griesemer

go/types: ignore artificial cycles introduced via method declarations

At the moment, method declarations are type-checked together with
they receiver base types. This is a known problem (to be fixed early
for Go 1.12) but with the new cycle detection algorithm now also
introduced artifical type cycles.

This change pushes a special marker on the cycle path in those cases
so that these cycles can be ignored.

Fixes #26124.

Change-Id: I64da4ccc32d4ae293da48880c892154a1c6ac3fe
Reviewed-on: https://go-review.googlesource.com/121757
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarAlan Donovan <adonovan@google.com>
parent fa71076d
...@@ -235,6 +235,14 @@ func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) { ...@@ -235,6 +235,14 @@ func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) {
// Indirections are used to break type cycles. // Indirections are used to break type cycles.
var indir = NewTypeName(token.NoPos, nil, "*", nil) var indir = NewTypeName(token.NoPos, nil, "*", nil)
// cutCycle is a sentinel type name that is pushed onto the object path
// to indicate that a cycle doesn't actually exist. This is currently
// needed to break cycles formed via method declarations because they
// are type-checked together with their receiver base types. Once methods
// are type-checked separately (see also TODO in Checker.typeDecl), we
// can get rid of this.
var cutCycle = NewTypeName(token.NoPos, nil, "!", nil)
// typeCycle checks if the cycle starting with obj is valid and // typeCycle checks if the cycle starting with obj is valid and
// reports an error if it is not. // reports an error if it is not.
// TODO(gri) rename s/typeCycle/cycle/ once we don't need the other // TODO(gri) rename s/typeCycle/cycle/ once we don't need the other
...@@ -270,10 +278,16 @@ func (check *Checker) typeCycle(obj Object) (isCycle bool) { ...@@ -270,10 +278,16 @@ func (check *Checker) typeCycle(obj Object) (isCycle bool) {
case *Const, *Var: case *Const, *Var:
nval++ nval++
case *TypeName: case *TypeName:
if obj == indir { switch {
case obj == indir:
ncycle-- // don't count (indirections are not objects) ncycle-- // don't count (indirections are not objects)
hasIndir = true hasIndir = true
} else if !check.objMap[obj].alias { case obj == cutCycle:
// The cycle is not real and only caused by the fact
// that we type-check methods when we type-check their
// receiver base types.
return false
case !check.objMap[obj].alias:
hasTDef = true hasTDef = true
} }
case *Func: case *Func:
...@@ -513,6 +527,16 @@ func (check *Checker) addMethodDecls(obj *TypeName) { ...@@ -513,6 +527,16 @@ func (check *Checker) addMethodDecls(obj *TypeName) {
} }
} }
if useCycleMarking {
// Suppress detection of type cycles occurring through method
// declarations - they wouldn't exist if methods were type-
// checked separately from their receiver base types. See also
// comment at the end of Checker.typeDecl.
// TODO(gri) Remove this once methods are type-checked separately.
check.push(cutCycle)
defer check.pop()
}
// type-check methods // type-check methods
for _, m := range methods { for _, m := range methods {
// spec: "For a base type, the non-blank names of methods bound // spec: "For a base type, the non-blank names of methods bound
......
...@@ -270,3 +270,27 @@ type issue25301c interface { ...@@ -270,3 +270,27 @@ type issue25301c interface {
} }
type notE = struct{} type notE = struct{}
// Test that method declarations don't introduce artificial cycles
// (issue #26124).
const CC TT = 1
type TT int
func (TT) MM() [CC]TT
// Reduced test case from issue #26124.
const preloadLimit LNumber = 128
type LNumber float64
func (LNumber) assertFunction() *LFunction
type LFunction struct {
GFunction LGFunction
}
type LGFunction func(*LState)
type LState struct {
reg *registry
}
type registry struct {
alloc *allocator
}
type allocator struct {
_ [int(preloadLimit)]int
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment