// identifier z in a variable declaration 'var z int' is found
// only in the Defs map, and identifiers denoting packages in
// 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
// Instances maps identifiers denoting parameterized types or functions to
{`package u1a; func _[_ interface{~int}]() {}`, `~int`, `~int`},
{`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`, `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 u1b; func _[_ ~int]() {}`, `~int`, `~int`},
{`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`, `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 {
// parseUnion parses uexpr as a union of expressions.
// The result is a Union type, or Typ[Invalid] for some errors.
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
- for _, x := range tlist {
- tilde, typ := parseTilde(check, x)
- if len(tlist) == 1 && !tilde {
+
+ var u Type
+ for i, x := range tlist {
+ term := parseTilde(check, x)
+ if len(tlist) == 1 && !term.tilde {
// Single type. Ok to return early because all relevant
// checks have been performed in parseTilde (no need to
// 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 {
- check.errorf(x, "cannot handle more than %d union terms (implementation limitation)", maxTermCount)
- check.recordTypeAndValue(uexpr, typexpr, Typ[Invalid], nil)
- return Typ[Invalid]
+ if u != Typ[Invalid] {
+ check.errorf(x, "cannot handle more than %d union terms (implementation limitation)", maxTermCount)
+ u = Typ[Invalid]
+ }
+ } else {
+ terms = append(terms, term)
+ u = &Union{terms}
+ }
+
+ if i > 0 {
+ check.recordTypeAndValue(blist[i-1], typexpr, u, nil)
}
- terms = append(terms, NewTerm(tilde, typ))
+ }
+
+ if u == Typ[Invalid] {
+ return u
}
// Check validity of terms.
}
})
- u := &Union{terms}
- check.recordTypeAndValue(uexpr, typexpr, u, nil)
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 {
x = op.X
tilde = true
}
- typ = check.typ(x)
+ typ := check.typ(x)
// 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
// parameter its constraint interface: if we embed a lone type parameter, we will
check.error(x, "cannot embed a type parameter")
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
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 {
- list = flattenUnion(list, o.X)
+ blist, tlist = flattenUnion(list, o.X)
+ blist = append(blist, o)
x = o.Y
}
- return append(list, x)
+ return blist, append(tlist, x)
}
{genericPkg + `u1a; func _[_ interface{~int}]() {}`, `~int`, `~int`},
{genericPkg + `u2a; func _[_ interface{int|string}]() {}`, `int | string`, `int|string`},
{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 + `u3b; 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|~bool}]() {}`, `int | string`, `int|string`},
+ {genericPkg + `u3a; func _[_ interface{int|string|~bool}]() {}`, `~bool`, `~bool`},
+ {genericPkg + `u3a; func _[_ interface{int|string|~float64|~bool}]() {}`, `int | string | ~float64`, `int|string|~float64`},
+
{genericPkg + `u0b; func _[_ int]() {}`, `int`, `int`},
{genericPkg + `u1b; func _[_ ~int]() {}`, `~int`, `~int`},
{genericPkg + `u2b; func _[_ int|string]() {}`, `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|~float64|~bool]() {}`, `int | string | ~float64`, `int|string|~float64`},
- {genericPkg + `u0b; type _ interface{int}`, `int`, `int`},
- {genericPkg + `u1b; type _ interface{~int}`, `~int`, `~int`},
- {genericPkg + `u2b; type _ interface{int|string}`, `int | string`, `int|string`},
- {genericPkg + `u3b; type _ interface{int|string|~bool}`, `int | string | ~bool`, `int|string|~bool`},
- {genericPkg + `u3b; type _ interface{int|string|~bool}`, `int | string`, `int|string`},
- {genericPkg + `u3b; type _ interface{int|string|~bool}`, `~bool`, `~bool`},
- {genericPkg + `u3b; type _ interface{int|string|~float64|~bool}`, `int | string | ~float64`, `int|string|~float64`},
+
+ {genericPkg + `u0c; type _ interface{int}`, `int`, `int`},
+ {genericPkg + `u1c; type _ interface{~int}`, `~int`, `~int`},
+ {genericPkg + `u2c; type _ interface{int|string}`, `int | string`, `int|string`},
+ {genericPkg + `u3c; type _ interface{int|string|~bool}`, `int | string | ~bool`, `int|string|~bool`},
+ {genericPkg + `u3c; type _ interface{int|string|~bool}`, `int | string`, `int|string`},
+ {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 {