mirror of
https://github.com/golang/go.git
synced 2024-09-21 18:38:37 +00:00
cmd/compile/internal/types2: record types for union subexpressions
This is a port of CL 371757 from go/types to types2, with minor adjustments for different error handling and AST. It also names the added API test cases more consistently. The same renaming was applied to the respective go/types file. Updates #50093 Change-Id: Iaa132106a197a207f831525432e62e9d452b17c9 Reviewed-on: https://go-review.googlesource.com/c/go/+/372475 Trust: Robert Griesemer <gri@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
4cda05d41a
commit
07ed86c57b
@ -202,12 +202,6 @@ type Info struct {
|
|||||||
// identifier z in a variable declaration 'var z int' is found
|
// identifier z in a variable declaration 'var z int' is found
|
||||||
// only in the Defs map, and identifiers denoting packages in
|
// only in the Defs map, and identifiers denoting packages in
|
||||||
// qualified identifiers are collected in the Uses map.
|
// qualified identifiers are collected in the Uses map.
|
||||||
//
|
|
||||||
// For binary expressions representing unions in constraint
|
|
||||||
// position or type elements in interfaces, a union type is
|
|
||||||
// recorded for the top-level expression only. For instance,
|
|
||||||
// given the constraint a|b|c, the union type for (a|b)|c
|
|
||||||
// is recorded, but not the union type for a|b.
|
|
||||||
Types map[syntax.Expr]TypeAndValue
|
Types map[syntax.Expr]TypeAndValue
|
||||||
|
|
||||||
// Instances maps identifiers denoting parameterized types or functions to
|
// Instances maps identifiers denoting parameterized types or functions to
|
||||||
|
@ -348,10 +348,25 @@ func TestTypesInfo(t *testing.T) {
|
|||||||
{`package u1a; func _[_ interface{~int}]() {}`, `~int`, `~int`},
|
{`package u1a; func _[_ interface{~int}]() {}`, `~int`, `~int`},
|
||||||
{`package u2a; func _[_ interface{int|string}]() {}`, `int | string`, `int|string`},
|
{`package u2a; func _[_ interface{int|string}]() {}`, `int | string`, `int|string`},
|
||||||
{`package u3a; func _[_ interface{int|string|~bool}]() {}`, `int | string | ~bool`, `int|string|~bool`},
|
{`package u3a; func _[_ interface{int|string|~bool}]() {}`, `int | string | ~bool`, `int|string|~bool`},
|
||||||
|
{`package u3a; func _[_ interface{int|string|~bool}]() {}`, `int | string`, `int|string`},
|
||||||
|
{`package u3a; func _[_ interface{int|string|~bool}]() {}`, `~bool`, `~bool`},
|
||||||
|
{`package u3a; func _[_ interface{int|string|~float64|~bool}]() {}`, `int | string | ~float64`, `int|string|~float64`},
|
||||||
|
|
||||||
{`package u0b; func _[_ int]() {}`, `int`, `int`},
|
{`package u0b; func _[_ int]() {}`, `int`, `int`},
|
||||||
{`package u1b; func _[_ ~int]() {}`, `~int`, `~int`},
|
{`package u1b; func _[_ ~int]() {}`, `~int`, `~int`},
|
||||||
{`package u2b; func _[_ int|string]() {}`, `int | string`, `int|string`},
|
{`package u2b; func _[_ int|string]() {}`, `int | string`, `int|string`},
|
||||||
{`package u3b; func _[_ int|string|~bool]() {}`, `int | string | ~bool`, `int|string|~bool`},
|
{`package u3b; func _[_ int|string|~bool]() {}`, `int | string | ~bool`, `int|string|~bool`},
|
||||||
|
{`package u3b; func _[_ int|string|~bool]() {}`, `int | string`, `int|string`},
|
||||||
|
{`package u3b; func _[_ int|string|~bool]() {}`, `~bool`, `~bool`},
|
||||||
|
{`package u3b; func _[_ int|string|~float64|~bool]() {}`, `int | string | ~float64`, `int|string|~float64`},
|
||||||
|
|
||||||
|
{`package u0c; type _ interface{int}`, `int`, `int`},
|
||||||
|
{`package u1c; type _ interface{~int}`, `~int`, `~int`},
|
||||||
|
{`package u2c; type _ interface{int|string}`, `int | string`, `int|string`},
|
||||||
|
{`package u3c; type _ interface{int|string|~bool}`, `int | string | ~bool`, `int|string|~bool`},
|
||||||
|
{`package u3c; type _ interface{int|string|~bool}`, `int | string`, `int|string`},
|
||||||
|
{`package u3c; type _ interface{int|string|~bool}`, `~bool`, `~bool`},
|
||||||
|
{`package u3c; type _ interface{int|string|~float64|~bool}`, `int | string | ~float64`, `int|string|~float64`},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
@ -48,23 +48,37 @@ const maxTermCount = 100
|
|||||||
// parseUnion parses uexpr as a union of expressions.
|
// parseUnion parses uexpr as a union of expressions.
|
||||||
// The result is a Union type, or Typ[Invalid] for some errors.
|
// The result is a Union type, or Typ[Invalid] for some errors.
|
||||||
func parseUnion(check *Checker, uexpr syntax.Expr) Type {
|
func parseUnion(check *Checker, uexpr syntax.Expr) Type {
|
||||||
tlist := flattenUnion(nil, uexpr)
|
blist, tlist := flattenUnion(nil, uexpr)
|
||||||
|
assert(len(blist) == len(tlist)-1)
|
||||||
|
|
||||||
var terms []*Term
|
var terms []*Term
|
||||||
for _, x := range tlist {
|
|
||||||
tilde, typ := parseTilde(check, x)
|
var u Type
|
||||||
if len(tlist) == 1 && !tilde {
|
for i, x := range tlist {
|
||||||
|
term := parseTilde(check, x)
|
||||||
|
if len(tlist) == 1 && !term.tilde {
|
||||||
// Single type. Ok to return early because all relevant
|
// Single type. Ok to return early because all relevant
|
||||||
// checks have been performed in parseTilde (no need to
|
// checks have been performed in parseTilde (no need to
|
||||||
// run through term validity check below).
|
// run through term validity check below).
|
||||||
return typ // typ already recorded through check.typ in parseTilde
|
return term.typ // typ already recorded through check.typ in parseTilde
|
||||||
}
|
}
|
||||||
if len(terms) >= maxTermCount {
|
if len(terms) >= maxTermCount {
|
||||||
check.errorf(x, "cannot handle more than %d union terms (implementation limitation)", maxTermCount)
|
if u != Typ[Invalid] {
|
||||||
check.recordTypeAndValue(uexpr, typexpr, Typ[Invalid], nil)
|
check.errorf(x, "cannot handle more than %d union terms (implementation limitation)", maxTermCount)
|
||||||
return Typ[Invalid]
|
u = Typ[Invalid]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
terms = append(terms, term)
|
||||||
|
u = &Union{terms}
|
||||||
}
|
}
|
||||||
terms = append(terms, NewTerm(tilde, typ))
|
|
||||||
|
if i > 0 {
|
||||||
|
check.recordTypeAndValue(blist[i-1], typexpr, u, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if u == Typ[Invalid] {
|
||||||
|
return u
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check validity of terms.
|
// Check validity of terms.
|
||||||
@ -106,17 +120,17 @@ func parseUnion(check *Checker, uexpr syntax.Expr) Type {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
u := &Union{terms}
|
|
||||||
check.recordTypeAndValue(uexpr, typexpr, u, nil)
|
|
||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseTilde(check *Checker, x syntax.Expr) (tilde bool, typ Type) {
|
func parseTilde(check *Checker, tx syntax.Expr) *Term {
|
||||||
|
x := tx
|
||||||
|
var tilde bool
|
||||||
if op, _ := x.(*syntax.Operation); op != nil && op.Op == syntax.Tilde {
|
if op, _ := x.(*syntax.Operation); op != nil && op.Op == syntax.Tilde {
|
||||||
x = op.X
|
x = op.X
|
||||||
tilde = true
|
tilde = true
|
||||||
}
|
}
|
||||||
typ = check.typ(x)
|
typ := check.typ(x)
|
||||||
// Embedding stand-alone type parameters is not permitted (issue #47127).
|
// Embedding stand-alone type parameters is not permitted (issue #47127).
|
||||||
// We don't need this restriction anymore if we make the underlying type of a type
|
// We don't need this restriction anymore if we make the underlying type of a type
|
||||||
// parameter its constraint interface: if we embed a lone type parameter, we will
|
// parameter its constraint interface: if we embed a lone type parameter, we will
|
||||||
@ -126,7 +140,11 @@ func parseTilde(check *Checker, x syntax.Expr) (tilde bool, typ Type) {
|
|||||||
check.error(x, "cannot embed a type parameter")
|
check.error(x, "cannot embed a type parameter")
|
||||||
typ = Typ[Invalid]
|
typ = Typ[Invalid]
|
||||||
}
|
}
|
||||||
return
|
term := NewTerm(tilde, typ)
|
||||||
|
if tilde {
|
||||||
|
check.recordTypeAndValue(tx, typexpr, &Union{[]*Term{term}}, nil)
|
||||||
|
}
|
||||||
|
return term
|
||||||
}
|
}
|
||||||
|
|
||||||
// overlappingTerm reports the index of the term x in terms which is
|
// overlappingTerm reports the index of the term x in terms which is
|
||||||
@ -147,10 +165,13 @@ func overlappingTerm(terms []*Term, y *Term) int {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func flattenUnion(list []syntax.Expr, x syntax.Expr) []syntax.Expr {
|
// flattenUnion walks a union type expression of the form A | B | C | ...,
|
||||||
|
// extracting both the binary exprs (blist) and leaf types (tlist).
|
||||||
|
func flattenUnion(list []syntax.Expr, x syntax.Expr) (blist, tlist []syntax.Expr) {
|
||||||
if o, _ := x.(*syntax.Operation); o != nil && o.Op == syntax.Or {
|
if o, _ := x.(*syntax.Operation); o != nil && o.Op == syntax.Or {
|
||||||
list = flattenUnion(list, o.X)
|
blist, tlist = flattenUnion(list, o.X)
|
||||||
|
blist = append(blist, o)
|
||||||
x = o.Y
|
x = o.Y
|
||||||
}
|
}
|
||||||
return append(list, x)
|
return blist, append(tlist, x)
|
||||||
}
|
}
|
||||||
|
@ -379,9 +379,10 @@ func TestTypesInfo(t *testing.T) {
|
|||||||
{genericPkg + `u1a; func _[_ interface{~int}]() {}`, `~int`, `~int`},
|
{genericPkg + `u1a; func _[_ interface{~int}]() {}`, `~int`, `~int`},
|
||||||
{genericPkg + `u2a; func _[_ interface{int|string}]() {}`, `int | string`, `int|string`},
|
{genericPkg + `u2a; func _[_ interface{int|string}]() {}`, `int | string`, `int|string`},
|
||||||
{genericPkg + `u3a; func _[_ interface{int|string|~bool}]() {}`, `int | string | ~bool`, `int|string|~bool`},
|
{genericPkg + `u3a; func _[_ interface{int|string|~bool}]() {}`, `int | string | ~bool`, `int|string|~bool`},
|
||||||
{genericPkg + `u3b; func _[_ interface{int|string|~bool}]() {}`, `int | string`, `int|string`},
|
{genericPkg + `u3a; func _[_ interface{int|string|~bool}]() {}`, `int | string`, `int|string`},
|
||||||
{genericPkg + `u3b; func _[_ interface{int|string|~bool}]() {}`, `~bool`, `~bool`},
|
{genericPkg + `u3a; func _[_ interface{int|string|~bool}]() {}`, `~bool`, `~bool`},
|
||||||
{genericPkg + `u3b; func _[_ interface{int|string|~float64|~bool}]() {}`, `int | string | ~float64`, `int|string|~float64`},
|
{genericPkg + `u3a; func _[_ interface{int|string|~float64|~bool}]() {}`, `int | string | ~float64`, `int|string|~float64`},
|
||||||
|
|
||||||
{genericPkg + `u0b; func _[_ int]() {}`, `int`, `int`},
|
{genericPkg + `u0b; func _[_ int]() {}`, `int`, `int`},
|
||||||
{genericPkg + `u1b; func _[_ ~int]() {}`, `~int`, `~int`},
|
{genericPkg + `u1b; func _[_ ~int]() {}`, `~int`, `~int`},
|
||||||
{genericPkg + `u2b; func _[_ int|string]() {}`, `int | string`, `int|string`},
|
{genericPkg + `u2b; func _[_ int|string]() {}`, `int | string`, `int|string`},
|
||||||
@ -389,13 +390,14 @@ func TestTypesInfo(t *testing.T) {
|
|||||||
{genericPkg + `u3b; func _[_ int|string|~bool]() {}`, `int | string`, `int|string`},
|
{genericPkg + `u3b; func _[_ int|string|~bool]() {}`, `int | string`, `int|string`},
|
||||||
{genericPkg + `u3b; func _[_ int|string|~bool]() {}`, `~bool`, `~bool`},
|
{genericPkg + `u3b; func _[_ int|string|~bool]() {}`, `~bool`, `~bool`},
|
||||||
{genericPkg + `u3b; func _[_ int|string|~float64|~bool]() {}`, `int | string | ~float64`, `int|string|~float64`},
|
{genericPkg + `u3b; func _[_ int|string|~float64|~bool]() {}`, `int | string | ~float64`, `int|string|~float64`},
|
||||||
{genericPkg + `u0b; type _ interface{int}`, `int`, `int`},
|
|
||||||
{genericPkg + `u1b; type _ interface{~int}`, `~int`, `~int`},
|
{genericPkg + `u0c; type _ interface{int}`, `int`, `int`},
|
||||||
{genericPkg + `u2b; type _ interface{int|string}`, `int | string`, `int|string`},
|
{genericPkg + `u1c; type _ interface{~int}`, `~int`, `~int`},
|
||||||
{genericPkg + `u3b; type _ interface{int|string|~bool}`, `int | string | ~bool`, `int|string|~bool`},
|
{genericPkg + `u2c; type _ interface{int|string}`, `int | string`, `int|string`},
|
||||||
{genericPkg + `u3b; type _ interface{int|string|~bool}`, `int | string`, `int|string`},
|
{genericPkg + `u3c; type _ interface{int|string|~bool}`, `int | string | ~bool`, `int|string|~bool`},
|
||||||
{genericPkg + `u3b; type _ interface{int|string|~bool}`, `~bool`, `~bool`},
|
{genericPkg + `u3c; type _ interface{int|string|~bool}`, `int | string`, `int|string`},
|
||||||
{genericPkg + `u3b; type _ interface{int|string|~float64|~bool}`, `int | string | ~float64`, `int|string|~float64`},
|
{genericPkg + `u3c; type _ interface{int|string|~bool}`, `~bool`, `~bool`},
|
||||||
|
{genericPkg + `u3c; type _ interface{int|string|~float64|~bool}`, `int | string | ~float64`, `int|string|~float64`},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
Loading…
Reference in New Issue
Block a user