1
0
mirror of https://github.com/golang/go synced 2024-11-22 08:44:41 -07:00

cmd/compile/internal/noder: enable type aliases in type checker

This CL fixes an initialization loop during IR construction, that
stems from IR lacking first-class support for aliases. As a
workaround, we avoid publishing alias declarations until the RHS type
expression has been constructed.

Thanks to gri@ for investigating while I was out.

Fixes #66873.

Change-Id: I11e0d96ea6c357c295da47f44b6ec408edef89b7
Reviewed-on: https://go-review.googlesource.com/c/go/+/585399
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Auto-Submit: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Matthew Dempsky 2024-05-14 22:22:34 -07:00 committed by Gopher Robot
parent c3c97ad1bf
commit 31c8150082
5 changed files with 56 additions and 10 deletions

View File

@ -49,9 +49,7 @@ func checkFiles(m posMap, noders []*noder) (*types2.Package, *types2.Info) {
IgnoreBranchErrors: true, // parser already checked via syntax.CheckBranches mode
Importer: &importer,
Sizes: types2.SizesFor("gc", buildcfg.GOARCH),
// Currently, the compiler panics when using Alias types.
// TODO(gri) set to true once this is fixed (issue #66873)
EnableAlias: false,
EnableAlias: true,
}
if base.Flag.ErrorURL {
conf.ErrorURL = " [go.dev/e/%s]"

View File

@ -427,7 +427,9 @@ func (pr *pkgReader) typIdx(info typeInfo, dict *readerDict, wrapped bool) *type
r.dict = dict
typ := r.doTyp()
assert(typ != nil)
if typ == nil {
base.Fatalf("doTyp returned nil for info=%v", info)
}
// For recursive type declarations involving interfaces and aliases,
// above r.doTyp() call may have already set pr.typs[idx], so just
@ -741,7 +743,26 @@ func (pr *pkgReader) objIdxMayFail(idx pkgbits.Index, implicits, explicits []*ty
case pkgbits.ObjAlias:
name := do(ir.OTYPE, false)
setType(name, r.typ())
// Clumsy dance: the r.typ() call here might recursively find this
// type alias name, before we've set its type (#66873). So we
// temporarily clear sym.Def and then restore it later, if still
// unset.
hack := sym.Def == name
if hack {
sym.Def = nil
}
typ := r.typ()
if hack {
if sym.Def != nil {
name = sym.Def.(*ir.Name)
assert(name.Type() == typ)
return name, nil
}
sym.Def = name
}
setType(name, typ)
name.SetAlias(true)
return name, nil

View File

@ -488,6 +488,18 @@ func (w *writer) typInfo(info typeInfo) {
// typIdx also reports whether typ is a derived type; that is, whether
// its identity depends on type parameters.
func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) typeInfo {
// Strip non-global aliases, because they only appear in inline
// bodies anyway. Otherwise, they can cause types.Sym collisions
// (e.g., "main.C" for both of the local type aliases in
// test/fixedbugs/issue50190.go).
for {
if alias, ok := typ.(*types2.Alias); ok && !isGlobal(alias.Obj()) {
typ = alias.Rhs()
} else {
break
}
}
if idx, ok := pw.typsIdx[typ]; ok {
return typeInfo{idx: idx, derived: false}
}

View File

@ -47,7 +47,7 @@ var _ T0 = A0{}
// But aliases and original types cannot be used with new types based on them.
var _ N0 = T0{} // ERROR "cannot use T0{} \(value of type T0\) as N0 value in variable declaration"
var _ N0 = A0{} // ERROR "cannot use A0{} \(value of type T0\) as N0 value in variable declaration"
var _ N0 = A0{} // ERROR "cannot use A0{} \(value of type A0\) as N0 value in variable declaration"
var _ A5 = Value{}
@ -83,7 +83,7 @@ func _() {
var _ T0 = A0{}
var _ N0 = T0{} // ERROR "cannot use T0{} \(value of type T0\) as N0 value in variable declaration"
var _ N0 = A0{} // ERROR "cannot use A0{} \(value of type T0\) as N0 value in variable declaration"
var _ N0 = A0{} // ERROR "cannot use A0{} \(value of type A0\) as N0 value in variable declaration"
var _ A5 = Value{} // ERROR "cannot use Value{} \(value of type reflect\.Value\) as A5 value in variable declaration"
}
@ -92,10 +92,10 @@ func _() {
type _ = reflect.ValueOf // ERROR "reflect.ValueOf .*is not a type|expected type"
func (A1) m() {} // ERROR "cannot define new methods on non-local type int|may not define methods on non-local type"
func (A1) m() {} // ERROR "cannot define new methods on non-local type|may not define methods on non-local type"
func (A2) m() {} // ERROR "invalid receiver type"
func (A3) m() {} // ERROR "cannot define new methods on non-local type reflect.Value|may not define methods on non-local type"
func (A4) m() {} // ERROR "cannot define new methods on non-local type reflect.Value|may not define methods on non-local type"
func (A3) m() {} // ERROR "cannot define new methods on non-local type|may not define methods on non-local type"
func (A4) m() {} // ERROR "cannot define new methods on non-local type|may not define methods on non-local type"
type B1 = struct{}

View File

@ -0,0 +1,15 @@
// compile
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
func f(A) {}
type T int
type A = T
func (A) m() {}