1
0
mirror of https://github.com/golang/go synced 2024-11-21 23:34:42 -07:00

types2, go/types: fix instantiation of named type with generic alias

The typechecker is assuming that alias instances cannot be reached from
a named type. However, when type parameters on aliases are permited, it
can happen.

This CL changes the typechecker to propagate the correct named instance
is being expanded.

Updates #46477
Fixes #68580

Change-Id: Id0879021f4640c0fefe277701d5096c649413811
Reviewed-on: https://go-review.googlesource.com/c/go/+/601115
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>
This commit is contained in:
Cuong Manh Le 2024-07-25 17:17:44 +07:00 committed by Gopher Robot
parent d8c7230c97
commit 9b4b4ae585
7 changed files with 31 additions and 12 deletions

View File

@ -134,10 +134,10 @@ func (check *Checker) newAlias(obj *TypeName, rhs Type) *Alias {
// newAliasInstance creates a new alias instance for the given origin and type // newAliasInstance creates a new alias instance for the given origin and type
// arguments, recording pos as the position of its synthetic object (for error // arguments, recording pos as the position of its synthetic object (for error
// reporting). // reporting).
func (check *Checker) newAliasInstance(pos syntax.Pos, orig *Alias, targs []Type, ctxt *Context) *Alias { func (check *Checker) newAliasInstance(pos syntax.Pos, orig *Alias, targs []Type, expanding *Named, ctxt *Context) *Alias {
assert(len(targs) > 0) assert(len(targs) > 0)
obj := NewTypeName(pos, orig.obj.pkg, orig.obj.name, nil) obj := NewTypeName(pos, orig.obj.pkg, orig.obj.name, nil)
rhs := check.subst(pos, orig.fromRHS, makeSubstMap(orig.TypeParams().list(), targs), nil, ctxt) rhs := check.subst(pos, orig.fromRHS, makeSubstMap(orig.TypeParams().list(), targs), expanding, ctxt)
res := check.newAlias(obj, rhs) res := check.newAlias(obj, rhs)
res.orig = orig res.orig = orig
res.tparams = orig.tparams res.tparams = orig.tparams

View File

@ -11,6 +11,7 @@ import (
"cmd/compile/internal/syntax" "cmd/compile/internal/syntax"
"errors" "errors"
"fmt" "fmt"
"internal/buildcfg"
. "internal/types/errors" . "internal/types/errors"
) )
@ -126,8 +127,9 @@ func (check *Checker) instance(pos syntax.Pos, orig genericType, targs []Type, e
res = check.newNamedInstance(pos, orig, targs, expanding) // substituted lazily res = check.newNamedInstance(pos, orig, targs, expanding) // substituted lazily
case *Alias: case *Alias:
// TODO(gri) is this correct? if !buildcfg.Experiment.AliasTypeParams {
assert(expanding == nil) // Alias instances cannot be reached from Named types assert(expanding == nil) // Alias instances cannot be reached from Named types
}
tparams := orig.TypeParams() tparams := orig.TypeParams()
// TODO(gri) investigate if this is needed (type argument and parameter count seem to be correct here) // TODO(gri) investigate if this is needed (type argument and parameter count seem to be correct here)
@ -138,7 +140,7 @@ func (check *Checker) instance(pos syntax.Pos, orig genericType, targs []Type, e
return orig // nothing to do (minor optimization) return orig // nothing to do (minor optimization)
} }
return check.newAliasInstance(pos, orig, targs, ctxt) return check.newAliasInstance(pos, orig, targs, expanding, ctxt)
case *Signature: case *Signature:
assert(expanding == nil) // function instances cannot be reached from Named types assert(expanding == nil) // function instances cannot be reached from Named types

View File

@ -115,7 +115,7 @@ func (subst *subster) typ(typ Type) Type {
// that has a type argument for it. // that has a type argument for it.
targs, updated := subst.typeList(t.TypeArgs().list()) targs, updated := subst.typeList(t.TypeArgs().list())
if updated { if updated {
return subst.check.newAliasInstance(subst.pos, t.orig, targs, subst.ctxt) return subst.check.newAliasInstance(subst.pos, t.orig, targs, subst.expanding, subst.ctxt)
} }
case *Array: case *Array:

View File

@ -137,10 +137,10 @@ func (check *Checker) newAlias(obj *TypeName, rhs Type) *Alias {
// newAliasInstance creates a new alias instance for the given origin and type // newAliasInstance creates a new alias instance for the given origin and type
// arguments, recording pos as the position of its synthetic object (for error // arguments, recording pos as the position of its synthetic object (for error
// reporting). // reporting).
func (check *Checker) newAliasInstance(pos token.Pos, orig *Alias, targs []Type, ctxt *Context) *Alias { func (check *Checker) newAliasInstance(pos token.Pos, orig *Alias, targs []Type, expanding *Named, ctxt *Context) *Alias {
assert(len(targs) > 0) assert(len(targs) > 0)
obj := NewTypeName(pos, orig.obj.pkg, orig.obj.name, nil) obj := NewTypeName(pos, orig.obj.pkg, orig.obj.name, nil)
rhs := check.subst(pos, orig.fromRHS, makeSubstMap(orig.TypeParams().list(), targs), nil, ctxt) rhs := check.subst(pos, orig.fromRHS, makeSubstMap(orig.TypeParams().list(), targs), expanding, ctxt)
res := check.newAlias(obj, rhs) res := check.newAlias(obj, rhs)
res.orig = orig res.orig = orig
res.tparams = orig.tparams res.tparams = orig.tparams

View File

@ -14,6 +14,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"go/token" "go/token"
"internal/buildcfg"
. "internal/types/errors" . "internal/types/errors"
) )
@ -129,8 +130,9 @@ func (check *Checker) instance(pos token.Pos, orig genericType, targs []Type, ex
res = check.newNamedInstance(pos, orig, targs, expanding) // substituted lazily res = check.newNamedInstance(pos, orig, targs, expanding) // substituted lazily
case *Alias: case *Alias:
// TODO(gri) is this correct? if !buildcfg.Experiment.AliasTypeParams {
assert(expanding == nil) // Alias instances cannot be reached from Named types assert(expanding == nil) // Alias instances cannot be reached from Named types
}
tparams := orig.TypeParams() tparams := orig.TypeParams()
// TODO(gri) investigate if this is needed (type argument and parameter count seem to be correct here) // TODO(gri) investigate if this is needed (type argument and parameter count seem to be correct here)
@ -141,7 +143,7 @@ func (check *Checker) instance(pos token.Pos, orig genericType, targs []Type, ex
return orig // nothing to do (minor optimization) return orig // nothing to do (minor optimization)
} }
return check.newAliasInstance(pos, orig, targs, ctxt) return check.newAliasInstance(pos, orig, targs, expanding, ctxt)
case *Signature: case *Signature:
assert(expanding == nil) // function instances cannot be reached from Named types assert(expanding == nil) // function instances cannot be reached from Named types

View File

@ -118,7 +118,7 @@ func (subst *subster) typ(typ Type) Type {
// that has a type argument for it. // that has a type argument for it.
targs, updated := subst.typeList(t.TypeArgs().list()) targs, updated := subst.typeList(t.TypeArgs().list())
if updated { if updated {
return subst.check.newAliasInstance(subst.pos, t.orig, targs, subst.ctxt) return subst.check.newAliasInstance(subst.pos, t.orig, targs, subst.expanding, subst.ctxt)
} }
case *Array: case *Array:

View File

@ -0,0 +1,15 @@
// compile -goexperiment aliastypeparams
// 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 main
type A[P any] = struct{ _ P }
type N[P any] A[P]
func f[P any](N[P]) {}
var _ = f[int]