diff options
| author | Mark Freeman <mark@golang.org> | 2025-11-24 17:04:49 -0500 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2025-11-26 16:15:28 -0800 |
| commit | 3531ac23d4aac6bdd914f14f65ee5fdc5e6e98fa (patch) | |
| tree | 2e29591c6ee6b819f87e93f1986a4b491a3d8d84 /src/cmd | |
| parent | 2b8dbb35b0d6a5601ae9b6f1d1de106774251214 (diff) | |
| download | go-3531ac23d4aac6bdd914f14f65ee5fdc5e6e98fa.tar.xz | |
go/types, types2: replace setDefType with pending type check
Given a type definition of the form:
type T RHS
The setDefType function would set T.fromRHS as soon as we knew its
top-level type. For instance, in:
type S struct { ... }
S.fromRHS is set to a struct type before type-checking anything inside
the struct.
This permit access to the (incomplete) RHS type in a cyclic type
declaration. Accessing this information is fraught (as it's incomplete),
but was used for reporting certain types of cycles.
This CL replaces setDefType with a check that ensures no value of type
T is used before its RHS is set up.
This CL is strictly more complete than what setDefType achieved. For
instance, it enables correct reporting for the below cycles:
type A [unsafe.Sizeof(A{})]int
var v any = 42
type B [v.(B)]int
func f() C {
return C{}
}
type C [unsafe.Sizeof(f())]int
Fixes #76383
Fixes #76384
Change-Id: I9dfab5b708013b418fa66e43362bb4d8483fedec
Reviewed-on: https://go-review.googlesource.com/c/go/+/724140
Auto-Submit: Mark Freeman <markfreeman@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Diffstat (limited to 'src/cmd')
| -rw-r--r-- | src/cmd/compile/internal/types2/expr.go | 23 | ||||
| -rw-r--r-- | src/cmd/compile/internal/types2/typexpr.go | 16 |
2 files changed, 25 insertions, 14 deletions
diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index 39bf4055a3..9d7580cb01 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -993,6 +993,13 @@ func (check *Checker) rawExpr(T *target, x *operand, e syntax.Expr, hint Type, a check.nonGeneric(T, x) } + // Here, x is a value, meaning it has a type. If that type is pending, then we have + // a cycle. As an example: + // + // type T [unsafe.Sizeof(T{})]int + // + // has a cycle T->T which is deemed valid (by decl.go), but which is in fact invalid. + check.pendingType(x) check.record(x) return kind @@ -1027,6 +1034,22 @@ func (check *Checker) nonGeneric(T *target, x *operand) { } } +// If x has a pending type (i.e. its declaring object is on the object path), pendingType +// reports an error and invalidates x.mode and x.typ. +// Otherwise it leaves x alone. +func (check *Checker) pendingType(x *operand) { + if x.mode == invalid || x.mode == novalue { + return + } + if n, ok := Unalias(x.typ).(*Named); ok { + if i, ok := check.objPathIdx[n.obj]; ok { + check.cycleError(check.objPath, i) + x.mode = invalid + x.typ = Typ[Invalid] + } + } +} + // exprInternal contains the core of type checking of expressions. // Must only be called by rawExpr. // (See rawExpr for an explanation of the parameters.) diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index 303f782ac4..c3e40184f5 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -417,20 +417,8 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *TypeName) (T Type) { return typ } -func setDefType(def *TypeName, typ Type) { - if def != nil { - switch t := def.typ.(type) { - case *Alias: - t.fromRHS = typ - case *Basic: - assert(t == Typ[Invalid]) - case *Named: - t.fromRHS = typ - default: - panic(fmt.Sprintf("unexpected type %T", t)) - } - } -} +// TODO(markfreeman): Remove this function. +func setDefType(def *TypeName, typ Type) {} func (check *Checker) instantiatedType(x syntax.Expr, xlist []syntax.Expr, def *TypeName) (res Type) { if check.conf.Trace { |
