// Indirections are used to break type cycles.
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
// reports an error if it is not.
// TODO(gri) rename s/typeCycle/cycle/ once we don't need the other
case *Const, *Var:
nval++
case *TypeName:
- if obj == indir {
+ switch {
+ case obj == indir:
ncycle-- // don't count (indirections are not objects)
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
}
case *Func:
}
}
+ 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
for _, m := range methods {
// spec: "For a base type, the non-blank names of methods bound
}
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
+}