mirror of
https://github.com/golang/go.git
synced 2026-02-04 01:45:06 +03:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4aa1efed48 | ||
|
|
428533fab4 | ||
|
|
4b9b25a21d | ||
|
|
d69d093c77 | ||
|
|
c79ccd88ab | ||
|
|
8706c09622 | ||
|
|
2c6a889234 | ||
|
|
1edc1ccf15 | ||
|
|
a0c7e2620a | ||
|
|
c6b5b7e6e5 | ||
|
|
36d32da19f | ||
|
|
1e4dc06f1a | ||
|
|
d10b8192c0 | ||
|
|
bf366ef711 | ||
|
|
92644ff54a | ||
|
|
673d52b33a | ||
|
|
e3f9a4f2ae | ||
|
|
c827ddf9e5 | ||
|
|
aeced24498 | ||
|
|
f913f9dd1a | ||
|
|
a54f962c29 | ||
|
|
7f9a85f2d9 | ||
|
|
520f0d0401 | ||
|
|
0b38b0277e | ||
|
|
40f6480db6 | ||
|
|
839c0f3b3e | ||
|
|
ce427cf961 | ||
|
|
79cf7c839b | ||
|
|
9f40b4f7a4 | ||
|
|
9f5e2849e1 | ||
|
|
77a142486e | ||
|
|
fd5b9b7c07 | ||
|
|
6206d65235 | ||
|
|
9f2f0ee6ce | ||
|
|
cb5a598d7f | ||
|
|
e70ee95914 | ||
|
|
39d2f50919 |
@@ -1 +1,2 @@
|
||||
branch: master
|
||||
branch: release-branch.go1.18
|
||||
parent-branch: master
|
||||
|
||||
412
doc/go_spec.html
412
doc/go_spec.html
@@ -1,26 +1,16 @@
|
||||
<!--{
|
||||
"Title": "The Go Programming Language Specification - Go 1.18 Draft",
|
||||
"Subtitle": "Version of Feb 28, 2022",
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Version of March 10, 2022",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
<h2>Earlier version</h2>
|
||||
|
||||
<p>
|
||||
For the pre-Go1.18 specification without generics support see
|
||||
<a href="/doc/go1.17_spec.html">The Go Programming Language Specification</a>.
|
||||
</p>
|
||||
|
||||
<!-- TODO(gri) remove this before the final release -->
|
||||
<p><b>
|
||||
[For reviewers: Sections where we know of missing prose are marked like this. The markers will be removed before the release.]
|
||||
</b></p>
|
||||
|
||||
<h2 id="Introduction">Introduction</h2>
|
||||
|
||||
<p>
|
||||
This is a reference manual for the Go programming language. For
|
||||
more information and other documents, see <a href="/">golang.org</a>.
|
||||
This is the reference manual for the Go programming language.
|
||||
The pre-Go1.18 version, without generics, can be found
|
||||
<a href="/doc/go1.17_spec.html">here</a>.
|
||||
For more information and other documents, see <a href="/">golang.org</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -766,7 +756,7 @@ type given in its declaration, the type provided in the
|
||||
<code>new</code> call or composite literal, or the type of
|
||||
an element of a structured variable.
|
||||
Variables of interface type also have a distinct <i>dynamic type</i>,
|
||||
which is the concrete type of the value assigned to the variable at run time
|
||||
which is the (non-interface) type of the value assigned to the variable at run time
|
||||
(unless the value is the predeclared identifier <code>nil</code>,
|
||||
which has no type).
|
||||
The dynamic type may vary during execution but values stored in interface
|
||||
@@ -812,7 +802,7 @@ TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType
|
||||
<p>
|
||||
The language <a href="#Predeclared_identifiers">predeclares</a> certain type names.
|
||||
Others are introduced with <a href="#Type_declarations">type declarations</a>
|
||||
or <a href="#Type_parameter_lists">type parameter lists</a>.
|
||||
or <a href="#Type_parameter_declarations">type parameter lists</a>.
|
||||
<i>Composite types</i>—array, struct, pointer, function,
|
||||
interface, slice, map, and channel types—may be constructed using
|
||||
type literals.
|
||||
@@ -987,7 +977,7 @@ built-in function <a href="#Length_and_capacity"><code>cap(a)</code></a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A new, initialized slice value for a given element type <code>T</code> is
|
||||
A new, initialized slice value for a given element type <code>T</code> may be
|
||||
made using the built-in function
|
||||
<a href="#Making_slices_maps_and_channels"><code>make</code></a>,
|
||||
which takes a slice type
|
||||
@@ -1422,7 +1412,7 @@ interface {
|
||||
~int
|
||||
}
|
||||
|
||||
// An interface representing all types with underlying type int which implement the String method.
|
||||
// An interface representing all types with underlying type int that implement the String method.
|
||||
interface {
|
||||
~int
|
||||
String() string
|
||||
@@ -1455,32 +1445,32 @@ Union elements denote unions of type sets:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
// The Floats interface represents all floating-point types
|
||||
// The Float interface represents all floating-point types
|
||||
// (including any named types whose underlying types are
|
||||
// either float32 or float64).
|
||||
type Floats interface {
|
||||
type Float interface {
|
||||
~float32 | ~float64
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
In a union, a term cannot be a type parameter, and the type sets of all
|
||||
In a union, a term cannot be a <a href="#Type_parameter_declarations">type parameter</a>, and the type sets of all
|
||||
non-interface terms must be pairwise disjoint (the pairwise intersection of the type sets must be empty).
|
||||
Given a type parameter <code>P</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
interface {
|
||||
P // illegal: the term P is a type parameter
|
||||
int | P // illegal: the term P is a type parameter
|
||||
~int | MyInt // illegal: the type sets for ~int and MyInt are not disjoint (~int includes MyInt)
|
||||
float32 | Floats // overlapping type sets but Floats is an interface
|
||||
P // illegal: P is a type parameter
|
||||
int | P // illegal: P is a type parameter
|
||||
~int | MyInt // illegal: the type sets for ~int and MyInt are not disjoint (~int includes MyInt)
|
||||
float32 | Float // overlapping type sets but Float is an interface
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Implementation restriction:
|
||||
A union with more than one term cannot contain the
|
||||
A union (with more than one term) cannot contain the
|
||||
<a href="#Predeclared_identifiers">predeclared identifier</a> <code>comparable</code>
|
||||
or interfaces that specify methods, or embed <code>comparable</code> or interfaces
|
||||
that specify methods.
|
||||
@@ -1494,12 +1484,12 @@ non-interface types.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var x Floats // illegal: Floats is not a basic interface
|
||||
var x Float // illegal: Float is not a basic interface
|
||||
|
||||
var x interface{} = Floats(nil) // illegal
|
||||
var x interface{} = Float(nil) // illegal
|
||||
|
||||
type Floatish struct {
|
||||
f Floats // illegal
|
||||
f Float // illegal
|
||||
}
|
||||
</pre>
|
||||
|
||||
@@ -1545,7 +1535,7 @@ A type <code>T</code> implements an interface <code>I</code> if
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
A value <code>x</code> of type <code>T</code> implements an interface if <code>T</code>
|
||||
A value of type <code>T</code> implements an interface if <code>T</code>
|
||||
implements the interface.
|
||||
</p>
|
||||
|
||||
@@ -1701,10 +1691,9 @@ Each type <code>T</code> has an <i>underlying type</i>: If <code>T</code>
|
||||
is one of the predeclared boolean, numeric, or string types, or a type literal,
|
||||
the corresponding underlying type is <code>T</code> itself.
|
||||
Otherwise, <code>T</code>'s underlying type is the underlying type of the
|
||||
type to which <code>T</code> refers in its <a href="#Type_declarations">type
|
||||
declaration</a>. The underlying type of a type parameter is the
|
||||
underlying type of its <a href="#Type_constraints">type constraint</a>, which
|
||||
is always an interface.
|
||||
type to which <code>T</code> refers in its declaration.
|
||||
For a type parameter that is the underlying type of its
|
||||
<a href="#Type_constraints">type constraint</a>, which is always an interface.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -1755,7 +1744,7 @@ direction.
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
All other interfaces don't have a core type.
|
||||
No other interfaces have a core type.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -1775,7 +1764,7 @@ depending on the direction of the directional channels present.
|
||||
|
||||
<p>
|
||||
By definition, a core type is never a <a href="#Type_definitions">defined type</a>,
|
||||
<a href="#Type_parameter_lists">type parameter</a>, or
|
||||
<a href="#Type_parameter_declarations">type parameter</a>, or
|
||||
<a href="#Interface_types">interface type</a>.
|
||||
</p>
|
||||
|
||||
@@ -1795,7 +1784,7 @@ interface{ ~[]*data; String() string } // []*data
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Examples of interfaces whithout core types:
|
||||
Examples of interfaces without core types:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -1805,70 +1794,6 @@ interface{ chan int | chan<- string } // channels have different element
|
||||
interface{ <-chan int | chan<- int } // directional channels have different directions
|
||||
</pre>
|
||||
|
||||
<h3 id="Specific_types">Specific types</h3>
|
||||
|
||||
<p><b>
|
||||
[The definition of specific types is not quite correct yet.]
|
||||
</b></p>
|
||||
|
||||
<p>
|
||||
An interface specification that contains <a href="#Interface_types">type elements</a>
|
||||
defines a (possibly empty) set of <i>specific types</i>.
|
||||
Loosely speaking, these are the types <code>T</code> that appear in the
|
||||
interface definition in terms of the form <code>T</code>, <code>~T</code>,
|
||||
or in unions of such terms.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
More precisely, for a given interface, the set of specific types corresponds to
|
||||
the set 𝑅 of representative types of the interface, if 𝑅 is non-empty and finite.
|
||||
Otherwise, if 𝑅 is empty or infinite, the interface has <i>no specific types</i>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For a given interface, type element or type term, the set 𝑅 of representative types is defined as follows:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>For an interface with no type elements, 𝑅 is the (infinite) set of all types.
|
||||
</li>
|
||||
|
||||
<li>For an interface with type elements,
|
||||
𝑅 is the intersection of the representative types of its type elements.
|
||||
</li>
|
||||
|
||||
<li>For a non-interface type term <code>T</code> or a term of the form <code>~T</code>,
|
||||
𝑅 is the set consisting of the type <code>T</code>.
|
||||
</li>
|
||||
|
||||
<li>For a <i>union</i> of terms
|
||||
<code>t<sub>1</sub>|t<sub>2</sub>|…|t<sub>n</sub></code>,
|
||||
𝑅 is the union of the representative types of the terms.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
An interface may have specific types even if its <a href="#Interface_types">type set</a>
|
||||
is empty.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Examples of interfaces with their specific types:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
interface{} // no specific types
|
||||
interface{ int } // int
|
||||
interface{ ~string } // string
|
||||
interface{ int|~string } // int, string
|
||||
interface{ Celsius|Kelvin } // Celsius, Kelvin
|
||||
interface{ float64|any } // no specific types (union is all types)
|
||||
interface{ int; m() } // int (but type set is empty because int has no method m)
|
||||
interface{ ~int; m() } // int (but type set is infinite because many integer types have a method m)
|
||||
interface{ int; any } // int
|
||||
interface{ int; string } // no specific types (intersection is empty)
|
||||
</pre>
|
||||
|
||||
<h3 id="Type_identity">Type identity</h3>
|
||||
|
||||
<p>
|
||||
@@ -1973,21 +1898,21 @@ defined type while the latter is a type literal
|
||||
<h3 id="Assignability">Assignability</h3>
|
||||
|
||||
<p>
|
||||
A value <code>x</code> is <i>assignable</i> to a <a href="#Variables">variable</a> of type <code>T</code>
|
||||
A value <code>x</code> of type <code>V</code> is <i>assignable</i> to a <a href="#Variables">variable</a> of type <code>T</code>
|
||||
("<code>x</code> is assignable to <code>T</code>") if one of the following conditions applies:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<code>x</code>'s type is identical to <code>T</code>.
|
||||
<code>V</code> and <code>T</code> are identical.
|
||||
</li>
|
||||
<li>
|
||||
<code>x</code>'s type <code>V</code> and <code>T</code> have identical
|
||||
<code>V</code> and <code>T</code> have identical
|
||||
<a href="#Underlying_types">underlying types</a> and at least one of <code>V</code>
|
||||
or <code>T</code> is not a <a href="#Types">named type</a>.
|
||||
</li>
|
||||
<li>
|
||||
<code>x</code>'s type <code>V</code> and <code>T</code> are channel types with
|
||||
<code>V</code> and <code>T</code> are channel types with
|
||||
identical element types, <code>V</code> is a bidirectional channel,
|
||||
and at least one of <code>V</code> or <code>T</code> is not a <a href="#Types">named type</a>.
|
||||
</li>
|
||||
@@ -2008,25 +1933,24 @@ by a value of type <code>T</code>.
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Additionally, if <code>x</code>'s type <code>V</code> or <code>T</code> are type parameters
|
||||
with <a href="#Specific_types">specific types</a>, <code>x</code>
|
||||
Additionally, if <code>x</code>'s type <code>V</code> or <code>T</code> are type parameters, <code>x</code>
|
||||
is assignable to a variable of type <code>T</code> if one of the following conditions applies:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<code>x</code> is the predeclared identifier <code>nil</code>, <code>T</code> is
|
||||
a type parameter, and <code>x</code> is assignable to each specific type of
|
||||
<code>T</code>.
|
||||
a type parameter, and <code>x</code> is assignable to each type in
|
||||
<code>T</code>'s type set.
|
||||
</li>
|
||||
<li>
|
||||
<code>V</code> is not a <a href="#Types">named type</a>, <code>T</code> is
|
||||
a type parameter, and <code>x</code> is assignable to each specific type of
|
||||
<code>T</code>.
|
||||
a type parameter, and <code>x</code> is assignable to each type in
|
||||
<code>T</code>'s type set.
|
||||
</li>
|
||||
<li>
|
||||
<code>V</code> is a type parameter and <code>T</code> is not a named type,
|
||||
and values of each specific type of <code>V</code> are assignable
|
||||
and values of each type in <code>V</code>'s type set are assignable
|
||||
to <code>T</code>.
|
||||
</li>
|
||||
</ul>
|
||||
@@ -2036,7 +1960,7 @@ to <code>T</code>.
|
||||
<p>
|
||||
A <a href="#Constants">constant</a> <code>x</code> is <i>representable</i>
|
||||
by a value of type <code>T</code>,
|
||||
where <code>T</code> is not a <a href="#Type_parameter_lists">type parameter</a>,
|
||||
where <code>T</code> is not a <a href="#Type_parameter_declarations">type parameter</a>,
|
||||
if one of the following conditions applies:
|
||||
</p>
|
||||
|
||||
@@ -2061,9 +1985,9 @@ are representable by values of <code>T</code>'s component type (<code>float32</c
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
If <code>T</code> is a type parameter with <a href="#Specific_types">specific types</a>,
|
||||
If <code>T</code> is a type parameter,
|
||||
<code>x</code> is representable by a value of type <code>T</code> if <code>x</code> is representable
|
||||
by a value of each specific type of <code>T</code>.
|
||||
by a value of each type in <code>T</code>'s type set.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -2176,6 +2100,7 @@ Blocks nest and influence <a href="#Declarations_and_scope">scoping</a>.
|
||||
A <i>declaration</i> binds a non-<a href="#Blank_identifier">blank</a> identifier to a
|
||||
<a href="#Constant_declarations">constant</a>,
|
||||
<a href="#Type_declarations">type</a>,
|
||||
<a href="#Type_parameter_declarations">type parameter</a>,
|
||||
<a href="#Variable_declarations">variable</a>,
|
||||
<a href="#Function_declarations">function</a>,
|
||||
<a href="#Labeled_statements">label</a>, or
|
||||
@@ -2220,13 +2145,13 @@ Go is lexically scoped using <a href="#Blocks">blocks</a>:
|
||||
<li>The scope of an identifier denoting a method receiver, function parameter,
|
||||
or result variable is the function body.</li>
|
||||
|
||||
<li>The scope of an identifier denoting a type parameter of a generic function
|
||||
<li>The scope of an identifier denoting a type parameter of a function
|
||||
or declared by a method receiver is the function body and all parameter lists of the
|
||||
function.
|
||||
</li>
|
||||
|
||||
<li>The scope of an identifier denoting a type parameter of a generic type
|
||||
begins after the name of the generic type and ends at the end
|
||||
<li>The scope of an identifier denoting a type parameter of a type
|
||||
begins after the name of the type and ends at the end
|
||||
of the TypeSpec.</li>
|
||||
|
||||
<li>The scope of a constant or variable identifier declared
|
||||
@@ -2512,7 +2437,7 @@ type (
|
||||
|
||||
type TreeNode struct {
|
||||
left, right *TreeNode
|
||||
value *Comparable
|
||||
value any
|
||||
}
|
||||
|
||||
type Block interface {
|
||||
@@ -2573,7 +2498,7 @@ func (tz TimeZone) String() string {
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If the type definition specifies <a href="#Type_parameter_lists">type parameters</a>,
|
||||
If the type definition specifies <a href="#Type_parameter_declarations">type parameters</a>,
|
||||
the type name denotes a <i>generic type</i>.
|
||||
Generic types must be <a href="#Instantiations">instantiated</a> when they
|
||||
are used.
|
||||
@@ -2584,15 +2509,10 @@ type List[T any] struct {
|
||||
next *List[T]
|
||||
value T
|
||||
}
|
||||
|
||||
type Tree[T constraints.Ordered] struct {
|
||||
left, right *Tree[T]
|
||||
value T
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The given type cannot be a type parameter in a type definition.
|
||||
In a type definition the given type cannot be a type parameter.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -2604,8 +2524,8 @@ func f[T any]() {
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
A generic type may also have methods associated with it. In this case,
|
||||
the method receivers must declare the same number of type parameters as
|
||||
A generic type may also have <a href="#Method_declarations">methods</a> associated with it.
|
||||
In this case, the method receivers must declare the same number of type parameters as
|
||||
present in the generic type definition.
|
||||
</p>
|
||||
|
||||
@@ -2614,7 +2534,7 @@ present in the generic type definition.
|
||||
func (l *List[T]) Len() int { … }
|
||||
</pre>
|
||||
|
||||
<h3 id="Type_parameter_lists">Type parameter lists</h3>
|
||||
<h3 id="Type_parameter_declarations">Type parameter declarations</h3>
|
||||
|
||||
<p>
|
||||
A type parameter list declares the <i>type parameters</i> of a generic function or type declaration.
|
||||
@@ -2653,22 +2573,22 @@ has a corresponding (meta-)type which is called its
|
||||
|
||||
<p>
|
||||
A parsing ambiguity arises when the type parameter list for a generic type
|
||||
declares a single type parameter with a type constraint of the form <code>*C</code>
|
||||
or <code>(C)</code> where <code>C</code> is not a (possibly parenthesized)
|
||||
<a href="#Types">type literal</a>:
|
||||
declares a single type parameter <code>P</code> with a constraint <code>C</code>
|
||||
such that the text <code>P C</code> forms a valid expression:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type T[P *C] …
|
||||
type T[P (C)] …
|
||||
type T[P *C|Q] …
|
||||
…
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
In these rare cases, the type parameter declaration is indistinguishable from
|
||||
the expressions <code>P*C</code> or <code>P(C)</code> and the type declaration
|
||||
is parsed as an array type declaration.
|
||||
To resolve the ambiguity, embed the constraint in an interface or use a trailing
|
||||
comma:
|
||||
In these rare cases, the type parameter list is indistinguishable from an
|
||||
expression and the type declaration is parsed as an array type declaration.
|
||||
To resolve the ambiguity, embed the constraint in an
|
||||
<a href="#Interface_types">interface</a> or use a trailing comma:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -2682,6 +2602,11 @@ of a <a href="#Method_declarations">method declaration</a> associated
|
||||
with a generic type.
|
||||
</p>
|
||||
|
||||
<!--
|
||||
This section needs to explain if and what kind of cycles are permitted
|
||||
using type parameters in a type parameter list.
|
||||
-->
|
||||
|
||||
<h4 id="Type_constraints">Type constraints</h4>
|
||||
|
||||
<p>
|
||||
@@ -2701,10 +2626,10 @@ the enclosing <code>interface{ … }</code> may be omitted for convenience:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
[T *P] // = [T interface{*P}]
|
||||
[T ~int] // = [T interface{~int}]
|
||||
[T int|string] // = [T interface{int|string}]
|
||||
type Constraint ~int // illegal: ~int is not inside a type parameter list
|
||||
[T []P] // = [T interface{[]P}]
|
||||
[T ~int] // = [T interface{~int}]
|
||||
[T int|string] // = [T interface{int|string}]
|
||||
type Constraint ~int // illegal: ~int is not inside a type parameter list
|
||||
</pre>
|
||||
|
||||
<!--
|
||||
@@ -2716,7 +2641,7 @@ other interfaces based on their type sets. But this should get us going for now.
|
||||
<p>
|
||||
The <a href="#Predeclared_identifiers">predeclared</a>
|
||||
<a href="#Interface_types">interface type</a> <code>comparable</code>
|
||||
denotes the set of all concrete (non-interface) types that are
|
||||
denotes the set of all non-interface types that are
|
||||
<a href="#Comparison_operators">comparable</a>. Specifically,
|
||||
a type <code>T</code> implements <code>comparable</code> if:
|
||||
</p>
|
||||
@@ -2897,14 +2822,14 @@ func IndexRune(s string, r rune) int {
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If the function declaration specifies <a href="#Type_parameter_lists">type parameters</a>,
|
||||
If the function declaration specifies <a href="#Type_parameter_declarations">type parameters</a>,
|
||||
the function name denotes a <i>generic function</i>.
|
||||
Generic functions must be <a href="#Instantiations">instantiated</a> when they
|
||||
are used.
|
||||
A generic function must be <a href="#Instantiations">instantiated</a> before it can be
|
||||
called or used as a value.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func min[T constraints.Ordered](x, y T) T {
|
||||
func min[T ~int|~float64](x, y T) T {
|
||||
if x < y {
|
||||
return x
|
||||
}
|
||||
@@ -2963,7 +2888,7 @@ the non-blank method and field names must be distinct.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Given defined type <code>Point</code>, the declarations
|
||||
Given defined type <code>Point</code> the declarations
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -2987,13 +2912,10 @@ to the base type <code>Point</code>.
|
||||
If the receiver base type is a <a href="#Type_declarations">generic type</a>, the
|
||||
receiver specification must declare corresponding type parameters for the method
|
||||
to use. This makes the receiver type parameters available to the method.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Syntactically, this type parameter declaration looks like an
|
||||
<a href="#Instantiations">instantiation</a> of the receiver base type, except that
|
||||
the type arguments are the type parameters being declared, one for each type parameter
|
||||
of the receiver base type.
|
||||
<a href="#Instantiations">instantiation</a> of the receiver base type: the type
|
||||
arguments must be identifiers denoting the type parameters being declared, one
|
||||
for each type parameter of the receiver base type.
|
||||
The type parameter names do not need to match their corresponding parameter names in the
|
||||
receiver base type definition, and all non-blank parameter names must be unique in the
|
||||
receiver parameter section and the method signature.
|
||||
@@ -3007,8 +2929,8 @@ type Pair[A, B any] struct {
|
||||
b B
|
||||
}
|
||||
|
||||
func (p Pair[A, B]) Swap() Pair[B, A] { return Pair[B, A]{p.b, p.a} }
|
||||
func (p Pair[First, _]) First() First { return p.a }
|
||||
func (p Pair[A, B]) Swap() Pair[B, A] { … } // receiver declares A, B
|
||||
func (p Pair[First, _]) First() First { … } // receiver declares First, corresponds to A in Pair
|
||||
</pre>
|
||||
|
||||
<h2 id="Expressions">Expressions</h2>
|
||||
@@ -3048,6 +2970,14 @@ The <a href="#Blank_identifier">blank identifier</a> may appear as an
|
||||
operand only on the left-hand side of an <a href="#Assignments">assignment</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Implementation restriction: A compiler need not report an error if an operand's
|
||||
type is a <a href="#Type_parameter_declarations">type parameter</a> with an empty
|
||||
<a href="#Interface_types">type set</a>. Functions with such type parameters
|
||||
cannot be <a href="#Instantiations">instantiated</a>; any attempt will lead
|
||||
to an error at the instantiation site.
|
||||
</p>
|
||||
|
||||
<h3 id="Qualified_identifiers">Qualified identifiers</h3>
|
||||
|
||||
<p>
|
||||
@@ -3354,10 +3284,6 @@ f.p[i].x()
|
||||
|
||||
<h3 id="Selectors">Selectors</h3>
|
||||
|
||||
<p><b>
|
||||
[This section is missing rules for x.f where x's type is a type parameter and f is a field.]
|
||||
</b></p>
|
||||
|
||||
<p>
|
||||
For a <a href="#Primary_expressions">primary expression</a> <code>x</code>
|
||||
that is not a <a href="#Package_clause">package name</a>, the
|
||||
@@ -3758,7 +3684,7 @@ The following rules apply:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If <code>a</code> is not a map:
|
||||
If <code>a</code> is neither a map nor a type parameter:
|
||||
</p>
|
||||
<ul>
|
||||
<li>the index <code>x</code> must be an untyped constant or its
|
||||
@@ -3827,23 +3753,22 @@ For <code>a</code> of <a href="#Map_types">map type</a> <code>M</code>:
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
For <code>a</code> of <a href="#Type_parameter_lists">type parameter type</a> <code>P</code>:
|
||||
For <code>a</code> of <a href="#Type_parameter_declarations">type parameter type</a> <code>P</code>:
|
||||
</p>
|
||||
<ul>
|
||||
<li><code>P</code> must have <a href="#Specific_types">specific types</a>.</li>
|
||||
<li>The index expression <code>a[x]</code> must be valid for values
|
||||
of all specific types of <code>P</code>.</li>
|
||||
<li>The element types of all specific types of <code>P</code> must be identical.
|
||||
of all types in <code>P</code>'s type set.</li>
|
||||
<li>The element types of all types in <code>P</code>'s type set must be identical.
|
||||
In this context, the element type of a string type is <code>byte</code>.</li>
|
||||
<li>If there is a map type among the specific types of <code>P</code>,
|
||||
all specific types must be map types, and the respective key types
|
||||
<li>If there is a map type in the type set of <code>P</code>,
|
||||
all types in that type set must be map types, and the respective key types
|
||||
must be all identical.</li>
|
||||
<li><code>a[x]</code> is the array, slice, or string element at index <code>x</code>,
|
||||
or the map element with key <code>x</code> of the type argument
|
||||
that <code>P</code> is instantiated with, and the type of <code>a[x]</code> is
|
||||
the type of the (identical) element types.</li>
|
||||
<li><code>a[x]</code> may not be assigned to if the specific types of <code>P</code>
|
||||
include string types.
|
||||
<li><code>a[x]</code> may not be assigned to if <code>P</code>'s type set
|
||||
includes string types.
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
@@ -4021,7 +3946,7 @@ If the indices are out of range at run time, a <a href="#Run_time_panics">run-ti
|
||||
|
||||
<p>
|
||||
For an expression <code>x</code> of <a href="#Interface_types">interface type</a>,
|
||||
but not a <a href="#Type_parameter_lists">type parameter</a>, and a type <code>T</code>,
|
||||
but not a <a href="#Type_parameter_declarations">type parameter</a>, and a type <code>T</code>,
|
||||
the primary expression
|
||||
</p>
|
||||
|
||||
@@ -4236,7 +4161,7 @@ with the same underlying array.
|
||||
<p>
|
||||
A generic function or type is <i>instantiated</i> by substituting <i>type arguments</i>
|
||||
for the type parameters.
|
||||
Instantiation proceeds in two phases:
|
||||
Instantiation proceeds in two steps:
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
@@ -4249,7 +4174,7 @@ including the type parameter list itself and any types in that list.
|
||||
|
||||
<li>
|
||||
After substitution, each type argument must <a href="#Interface_types">implement</a>
|
||||
the <a href="#Type_parameter_lists">constraint</a> (instantiated, if necessary)
|
||||
the <a href="#Type_parameter_declarations">constraint</a> (instantiated, if necessary)
|
||||
of the corresponding type parameter. Otherwise instantiation fails.
|
||||
</li>
|
||||
</ol>
|
||||
@@ -4262,55 +4187,57 @@ instantiating a function produces a new non-generic function.
|
||||
<pre>
|
||||
type parameter list type arguments after substitution
|
||||
|
||||
[P any] int [int any]
|
||||
[S ~[]E, E any] []int, int [[]int ~[]int, int any]
|
||||
[P io.Writer] string [string io.Writer] // illegal: string doesn't implement io.Writer
|
||||
[P any] int int implements any
|
||||
[S ~[]E, E any] []int, int []int implements ~[]int, int implements any
|
||||
[P io.Writer] string illegal: string doesn't implement io.Writer
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Type arguments may be provided explicitly, or they may be partially or completely
|
||||
<a href="#Type_inference">inferred</a>.
|
||||
A partially provided type argument list cannot be empty; there must be at least the
|
||||
first argument.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type T[P1 ~int, P2 ~[]P1] struct{ … }
|
||||
|
||||
T[] // illegal: at least the first type argument must be present, even if it could be inferred
|
||||
T[int] // argument for P1 explicitly provided, argument for P2 inferred
|
||||
T[int, []int] // both arguments explicitly provided
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
A partial type argument list specifies a prefix of the full list of type arguments, leaving
|
||||
the remaining arguments to be inferred. Loosely speaking, type arguments may be omitted from
|
||||
"right to left".
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Generic types, and generic functions that are not <a href="#Calls">called</a>,
|
||||
require a type argument list for instantiation; if the list is partial, all
|
||||
For a generic function, type arguments may be provided explicitly, or they
|
||||
may be partially or completely <a href="#Type_inference">inferred</a>.
|
||||
A generic function that is is <i>not</i> <a href="#Calls">called</a> requires a
|
||||
type argument list for instantiation; if the list is partial, all
|
||||
remaining type arguments must be inferrable.
|
||||
Calls to generic functions may provide a (possibly partial) type
|
||||
A generic function that is called may provide a (possibly partial) type
|
||||
argument list, or may omit it entirely if the omitted type arguments are
|
||||
inferrable from the ordinary (non-type) function arguments.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func min[T constraints.Ordered](x, y T) T { … }
|
||||
func min[T ~int|~float64](x, y T) T { … }
|
||||
|
||||
f := min // illegal: min must be instantiated when used without being called
|
||||
f := min // illegal: min must be instantiated with type arguments when used without being called
|
||||
minInt := min[int] // minInt has type func(x, y int) int
|
||||
a := minInt(2, 3) // a has value 2 of type int
|
||||
b := min[float64](2.0, 3) // b has value 2.0 of type float64
|
||||
c := min(b, -1) // c has value -1.0 of type float64
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
A partial type argument list cannot be empty; at least the first argument must be present.
|
||||
The list is a prefix of the full list of type arguments, leaving the remaining arguments
|
||||
to be inferred. Loosely speaking, type arguments may be omitted from "right to left".
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func apply[S ~[]E, E any](s S, f(E) E) S { … }
|
||||
|
||||
f0 := apply[] // illegal: type argument list cannot be empty
|
||||
f1 := apply[[]int] // type argument for S explicitly provided, type argument for E inferred
|
||||
f2 := apply[[]string, string] // both type arguments explicitly provided
|
||||
|
||||
var bytes []byte
|
||||
r := apply(bytes, func(byte) byte { … }) // both type arguments inferred from the function arguments
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
For a generic type, all type arguments must always be provided explicitly.
|
||||
</p>
|
||||
|
||||
<h3 id="Type_inference">Type inference</h3>
|
||||
|
||||
<p>
|
||||
Missing type arguments may be <i>inferred</i> by a series of steps, described below.
|
||||
Missing function type arguments may be <i>inferred</i> by a series of steps, described below.
|
||||
Each step attempts to use known information to infer additional type arguments.
|
||||
Type inference stops as soon as all type arguments are known.
|
||||
After type inference is complete, it is still necessary to substitute all type arguments
|
||||
@@ -4326,7 +4253,7 @@ Type inference is based on
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
a <a href="#Type_parameter_lists">type parameter list</a>
|
||||
a <a href="#Type_parameter_declarations">type parameter list</a>
|
||||
</li>
|
||||
<li>
|
||||
a substitution map <i>M</i> initialized with the known type arguments, if any
|
||||
@@ -4491,9 +4418,8 @@ unresolved type parameters left.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Function argument type inference can be used when the function has ordinary parameters
|
||||
whose types are defined using the function's type parameters. Inference happens in two
|
||||
separate phases; each phase operates on a specific list of (parameter, argument) pairs:
|
||||
Inference happens in two separate phases; each phase operates on a specific list of
|
||||
(parameter, argument) pairs:
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
@@ -4550,7 +4476,7 @@ Example:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func min[T constraints.Ordered](x, y T) T
|
||||
func min[T ~int|~float64](x, y T) T
|
||||
|
||||
var x int
|
||||
min(x, 2.0) // T is int, inferred from typed argument x; 2.0 is assignable to int
|
||||
@@ -4841,9 +4767,8 @@ The bitwise logical and shift operators apply to integers only.
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Excluding shifts, if the operand type is a <a href="#Type_parameter_lists">type parameter</a>,
|
||||
it must have <a href="#Specific_types">specific types</a>, and the operator must
|
||||
apply to each specific type.
|
||||
If the operand type is a <a href="#Type_parameter_declarations">type parameter</a>,
|
||||
the operator must apply to each type in that type set.
|
||||
The operands are represented as values of the type argument that the type parameter
|
||||
is <a href="#Instantiations">instantiated</a> with, and the operation is computed
|
||||
with the precision of that type argument. For example, given the function:
|
||||
@@ -4866,11 +4791,6 @@ are computed with <code>float32</code> or <code>float64</code> precision,
|
||||
respectively, depending on the type argument for <code>F</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For shifts, the <a href="#Core_types">core type</a> of both operands must be
|
||||
an integer.
|
||||
</p>
|
||||
|
||||
<h4 id="Integer_operators">Integer operators</h4>
|
||||
|
||||
<p>
|
||||
@@ -5296,7 +5216,7 @@ as for non-constant <code>x</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Converting a constant to a type that is not a <a href="#Type_parameter_lists">type parameter</a>
|
||||
Converting a constant to a type that is not a <a href="#Type_parameter_declarations">type parameter</a>
|
||||
yields a typed constant.
|
||||
</p>
|
||||
|
||||
@@ -5351,7 +5271,7 @@ in any of these cases:
|
||||
<li>
|
||||
ignoring struct tags (see below),
|
||||
<code>x</code>'s type and <code>T</code> are not
|
||||
<a href="#Type_parameter_lists">type parameters</a> but have
|
||||
<a href="#Type_parameter_declarations">type parameters</a> but have
|
||||
<a href="#Type_identity">identical</a> <a href="#Types">underlying types</a>.
|
||||
</li>
|
||||
<li>
|
||||
@@ -5383,23 +5303,23 @@ in any of these cases:
|
||||
|
||||
<p>
|
||||
Additionally, if <code>T</code> or <code>x</code>'s type <code>V</code> are type
|
||||
parameters with <a href="#Specific_types">specific types</a>, <code>x</code>
|
||||
parameters, <code>x</code>
|
||||
can also be converted to type <code>T</code> if one of the following conditions applies:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Both <code>V</code> and <code>T</code> are type parameters and a value of each
|
||||
specific type of <code>V</code> can be converted to each specific type
|
||||
of <code>T</code>.
|
||||
type in <code>V</code>'s type set can be converted to each type in <code>T</code>'s
|
||||
type set.
|
||||
</li>
|
||||
<li>
|
||||
Only <code>V</code> is a type parameter and a value of each
|
||||
specific type of <code>V</code> can be converted to <code>T</code>.
|
||||
type in <code>V</code>'s type set can be converted to <code>T</code>.
|
||||
</li>
|
||||
<li>
|
||||
Only <code>T</code> is a type parameter and <code>x</code> can be converted to each
|
||||
specific type of <code>T</code>.
|
||||
type in <code>T</code>'s type set.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -6270,7 +6190,7 @@ switch x.(type) {
|
||||
Cases then match actual types <code>T</code> against the dynamic type of the
|
||||
expression <code>x</code>. As with type assertions, <code>x</code> must be of
|
||||
<a href="#Interface_types">interface type</a>, but not a
|
||||
<a href="#Type_parameter_lists">type parameter</a>, and each non-interface type
|
||||
<a href="#Type_parameter_declarations">type parameter</a>, and each non-interface type
|
||||
<code>T</code> listed in a case must implement the type of <code>x</code>.
|
||||
The types listed in the cases of a type switch must all be
|
||||
<a href="#Type_identity">different</a>.
|
||||
@@ -6352,7 +6272,7 @@ if v == nil {
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
A <a href="#Type_parameter_lists">type parameter</a> or a <a href="#Type_declarations">generic type</a>
|
||||
A <a href="#Type_parameter_declarations">type parameter</a> or a <a href="#Type_declarations">generic type</a>
|
||||
may be used as a type in a case. If upon <a href="#Instantiations">instantiation</a> that type turns
|
||||
out to duplicate another entry in the switch, the first matching case is chosen.
|
||||
</p>
|
||||
@@ -7093,10 +7013,9 @@ cap(s) [n]T, *[n]T array length (== n)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If the argument type is a <a href="#Type_parameter_lists">type parameter</a> <code>P</code>,
|
||||
<code>P</code> must have <a href="#Specific_types">specific types</a>, and
|
||||
If the argument type is a <a href="#Type_parameter_declarations">type parameter</a> <code>P</code>,
|
||||
the call <code>len(e)</code> (or <code>cap(e)</code> respectively) must be valid for
|
||||
each specific type of <code>P</code>.
|
||||
each type in <code>P</code>'s type set.
|
||||
The result is the length (or capacity, respectively) of the argument whose type
|
||||
corresponds to the type argument with which <code>P</code> was
|
||||
<a href="#Instantiations">instantiated</a>.
|
||||
@@ -7197,8 +7116,9 @@ make(T, n) channel buffered channel of type T, buffer size n
|
||||
|
||||
|
||||
<p>
|
||||
Each of the size arguments <code>n</code> and <code>m</code> must be of <a href="#Numeric_types">integer type</a>
|
||||
or an untyped <a href="#Constants">constant</a>.
|
||||
Each of the size arguments <code>n</code> and <code>m</code> must be of <a href="#Numeric_types">integer type</a>,
|
||||
have a <a href="#Interface_types">type set</a> containing only integer types,
|
||||
or be an untyped <a href="#Constants">constant</a>.
|
||||
A constant size argument must be non-negative and <a href="#Representability">representable</a>
|
||||
by a value of type <code>int</code>; if it is an untyped constant it is given type <code>int</code>.
|
||||
If both <code>n</code> and <code>m</code> are provided and are constant, then
|
||||
@@ -7235,9 +7155,9 @@ by the arguments overlaps.
|
||||
<p>
|
||||
The <a href="#Function_types">variadic</a> function <code>append</code>
|
||||
appends zero or more values <code>x</code> to a slice <code>s</code>
|
||||
and returns the resulting slice.
|
||||
and returns the resulting slice of the same type as <code>s</code>.
|
||||
The <a href="#Core_types">core type</a> of <code>s</code> must be a slice
|
||||
of the form <code>[]E</code>.
|
||||
of type <code>[]E</code>.
|
||||
The values <code>x</code> are passed to a parameter of type <code>...E</code>
|
||||
and the respective <a href="#Passing_arguments_to_..._parameters">parameter
|
||||
passing rules</a> apply.
|
||||
@@ -7247,7 +7167,7 @@ followed by <code>...</code>. This form appends the bytes of the string.
|
||||
</p>
|
||||
|
||||
<pre class="grammar">
|
||||
append(s S, x ...E) S // E is the element type of the core type of S
|
||||
append(s S, x ...E) S // core type of S is []E
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@@ -7317,9 +7237,8 @@ delete(m, k) // remove element m[k] from map m
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If the type of <code>m</code> is a <a href="#Type_parameter_lists">type parameter</a>,
|
||||
it must have <a href="#Specific_types">specific types</a>, all specific types
|
||||
must be maps, and they must all have identical key types.
|
||||
If the type of <code>m</code> is a <a href="#Type_parameter_declarations">type parameter</a>,
|
||||
all types in that type set must be maps, and they must all have identical key types.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -7330,10 +7249,6 @@ does not exist, <code>delete</code> is a no-op.
|
||||
|
||||
<h3 id="Complex_numbers">Manipulating complex numbers</h3>
|
||||
|
||||
<p><b>
|
||||
[We don't support generic arguments for these built-ins for Go 1.18.]
|
||||
</b></p>
|
||||
|
||||
<p>
|
||||
Three functions assemble and disassemble complex numbers.
|
||||
The built-in function <code>complex</code> constructs a complex
|
||||
@@ -7396,6 +7311,10 @@ const c = imag(b) // untyped constant -1.4
|
||||
_ = imag(3 << s) // illegal: 3 assumes complex type, cannot shift
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Arguments of type parameter type are not permitted.
|
||||
</p>
|
||||
|
||||
<h3 id="Handling_panics">Handling panics</h3>
|
||||
|
||||
<p> Two built-in functions, <code>panic</code> and <code>recover</code>,
|
||||
@@ -8004,11 +7923,17 @@ func Add(ptr Pointer, len IntegerType) Pointer
|
||||
func Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType
|
||||
</pre>
|
||||
|
||||
<!--
|
||||
These conversions also apply to type parameters with suitable core types.
|
||||
Determine if we can simply use core type insted of underlying type here,
|
||||
of if the general conversion rules take care of this.
|
||||
-->
|
||||
|
||||
<p>
|
||||
A <code>Pointer</code> is a <a href="#Pointer_types">pointer type</a> but a <code>Pointer</code>
|
||||
value may not be <a href="#Address_operators">dereferenced</a>.
|
||||
Any pointer or value of <a href="#Types">underlying type</a> <code>uintptr</code> can be converted to
|
||||
a type of underlying type <code>Pointer</code> and vice versa.
|
||||
Any pointer or value of <a href="#Types">underlying type</a> <code>uintptr</code> can be
|
||||
<a href="#Conversions">converted</a> to a type of underlying type <code>Pointer</code> and vice versa.
|
||||
The effect of converting between <code>Pointer</code> and <code>uintptr</code> is implementation-defined.
|
||||
</p>
|
||||
|
||||
@@ -8055,7 +7980,8 @@ uintptr(unsafe.Pointer(&x)) % unsafe.Alignof(x) == 0
|
||||
|
||||
<p>
|
||||
A (variable of) type <code>T</code> has <i>variable size</i> if <code>T</code>
|
||||
is a type parameter, or if it is an array or struct type containing elements
|
||||
is a <a href="#Type_parameter_declarations">type parameter</a>, or if it is an
|
||||
array or struct type containing elements
|
||||
or fields of variable size. Otherwise the size is <i>constant</i>.
|
||||
Calls to <code>Alignof</code>, <code>Offsetof</code>, and <code>Sizeof</code>
|
||||
are compile-time <a href="#Constant_expressions">constant expressions</a> of
|
||||
|
||||
@@ -362,7 +362,7 @@ func NewSendStmt(pos src.XPos, ch, value Node) *SendStmt {
|
||||
return n
|
||||
}
|
||||
|
||||
// A SwitchStmt is a switch statement: switch Init; Expr { Cases }.
|
||||
// A SwitchStmt is a switch statement: switch Init; Tag { Cases }.
|
||||
type SwitchStmt struct {
|
||||
miniStmt
|
||||
Tag Node
|
||||
|
||||
@@ -1179,6 +1179,26 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
||||
subst.g.newInsts = append(subst.g.newInsts, m.(*ir.ClosureExpr).Func)
|
||||
m.(*ir.ClosureExpr).SetInit(subst.list(x.Init()))
|
||||
|
||||
case ir.OSWITCH:
|
||||
m := m.(*ir.SwitchStmt)
|
||||
if m.Tag != nil && m.Tag.Op() == ir.OTYPESW {
|
||||
break // Nothing to do here for type switches.
|
||||
}
|
||||
if m.Tag != nil && !m.Tag.Type().IsInterface() && m.Tag.Type().HasShape() {
|
||||
// To implement a switch on a value that is or has a type parameter, we first convert
|
||||
// that thing we're switching on to an interface{}.
|
||||
m.Tag = assignconvfn(m.Tag, types.Types[types.TINTER])
|
||||
}
|
||||
for _, c := range m.Cases {
|
||||
for i, x := range c.List {
|
||||
// If we have a case that is or has a type parameter, convert that case
|
||||
// to an interface{}.
|
||||
if !x.Type().IsInterface() && x.Type().HasShape() {
|
||||
c.List[i] = assignconvfn(x, types.Types[types.TINTER])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
@@ -242,7 +242,7 @@ func transformCompare(n *ir.BinaryExpr) {
|
||||
aop, _ := typecheck.Assignop(rt, lt)
|
||||
if aop != ir.OXXX {
|
||||
types.CalcSize(rt)
|
||||
if rt.HasTParam() || rt.IsInterface() == lt.IsInterface() || rt.Size() >= 1<<16 {
|
||||
if rt.HasShape() || rt.IsInterface() == lt.IsInterface() || rt.Size() >= 1<<16 {
|
||||
r = ir.NewConvExpr(base.Pos, aop, lt, r)
|
||||
r.SetTypecheck(1)
|
||||
}
|
||||
|
||||
@@ -1430,7 +1430,7 @@ func WriteBasicTypes() {
|
||||
|
||||
type typeAndStr struct {
|
||||
t *types.Type
|
||||
short string // "short" here means NameString
|
||||
short string // "short" here means TypeSymName
|
||||
regular string
|
||||
}
|
||||
|
||||
|
||||
@@ -1851,7 +1851,10 @@ func (w *exportWriter) expr(n ir.Node) {
|
||||
n := n.(*ir.ClosureExpr)
|
||||
w.op(ir.OCLOSURE)
|
||||
w.pos(n.Pos())
|
||||
old := w.currPkg
|
||||
w.setPkg(n.Type().Pkg(), true)
|
||||
w.signature(n.Type())
|
||||
w.setPkg(old, true)
|
||||
|
||||
// Write out id for the Outer of each conditional variable. The
|
||||
// conditional variable itself for this closure will be re-created
|
||||
|
||||
@@ -1374,7 +1374,9 @@ func (r *importReader) node() ir.Node {
|
||||
case ir.OCLOSURE:
|
||||
//println("Importing CLOSURE")
|
||||
pos := r.pos()
|
||||
r.setPkg()
|
||||
typ := r.signature(nil, nil)
|
||||
r.setPkg()
|
||||
|
||||
// All the remaining code below is similar to (*noder).funcLit(), but
|
||||
// with Dcls and ClosureVars lists already set up
|
||||
|
||||
@@ -72,6 +72,7 @@ const (
|
||||
fmtDebug
|
||||
fmtTypeID
|
||||
fmtTypeIDName
|
||||
fmtTypeIDHash
|
||||
)
|
||||
|
||||
// Sym
|
||||
@@ -144,10 +145,21 @@ func symfmt(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) {
|
||||
if q := pkgqual(s.Pkg, verb, mode); q != "" {
|
||||
b.WriteString(q)
|
||||
b.WriteByte('.')
|
||||
if mode == fmtTypeIDName {
|
||||
switch mode {
|
||||
case fmtTypeIDName:
|
||||
// If name is a generic instantiation, it might have local package placeholders
|
||||
// in it. Replace those placeholders with the package name. See issue 49547.
|
||||
name = strings.Replace(name, LocalPkg.Prefix, q, -1)
|
||||
case fmtTypeIDHash:
|
||||
// If name is a generic instantiation, don't hash the instantiating types.
|
||||
// This isn't great, but it is safe. If we hash the instantiating types, then
|
||||
// we need to make sure they have just the package name. At this point, they
|
||||
// either have "", or the whole package path, and it is hard to reconcile
|
||||
// the two without depending on -p (which we might do someday).
|
||||
// See issue 51250.
|
||||
if i := strings.Index(name, "["); i >= 0 {
|
||||
name = name[:i]
|
||||
}
|
||||
}
|
||||
}
|
||||
b.WriteString(name)
|
||||
@@ -173,7 +185,7 @@ func pkgqual(pkg *Pkg, verb rune, mode fmtMode) string {
|
||||
case fmtDebug:
|
||||
return pkg.Name
|
||||
|
||||
case fmtTypeIDName:
|
||||
case fmtTypeIDName, fmtTypeIDHash:
|
||||
// dcommontype, typehash
|
||||
return pkg.Name
|
||||
|
||||
@@ -331,7 +343,7 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
|
||||
if t == AnyType || t == ByteType || t == RuneType {
|
||||
// in %-T mode collapse predeclared aliases with their originals.
|
||||
switch mode {
|
||||
case fmtTypeIDName, fmtTypeID:
|
||||
case fmtTypeIDName, fmtTypeIDHash, fmtTypeID:
|
||||
t = Types[t.Kind()]
|
||||
default:
|
||||
sconv2(b, t.Sym(), 'S', mode)
|
||||
@@ -422,7 +434,7 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
|
||||
case TPTR:
|
||||
b.WriteByte('*')
|
||||
switch mode {
|
||||
case fmtTypeID, fmtTypeIDName:
|
||||
case fmtTypeID, fmtTypeIDName, fmtTypeIDHash:
|
||||
if verb == 'S' {
|
||||
tconv2(b, t.Elem(), 'S', mode, visited)
|
||||
return
|
||||
@@ -484,7 +496,7 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
|
||||
case IsExported(f.Sym.Name):
|
||||
sconv2(b, f.Sym, 'S', mode)
|
||||
default:
|
||||
if mode != fmtTypeIDName {
|
||||
if mode != fmtTypeIDName && mode != fmtTypeIDHash {
|
||||
mode = fmtTypeID
|
||||
}
|
||||
sconv2(b, f.Sym, 'v', mode)
|
||||
@@ -554,7 +566,7 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
|
||||
b.WriteByte(byte(open))
|
||||
fieldVerb := 'v'
|
||||
switch mode {
|
||||
case fmtTypeID, fmtTypeIDName, fmtGo:
|
||||
case fmtTypeID, fmtTypeIDName, fmtTypeIDHash, fmtGo:
|
||||
// no argument names on function signature, and no "noescape"/"nosplit" tags
|
||||
fieldVerb = 'S'
|
||||
}
|
||||
@@ -688,7 +700,7 @@ func fldconv(b *bytes.Buffer, f *Field, verb rune, mode fmtMode, visited map[*Ty
|
||||
if name == ".F" {
|
||||
name = "F" // Hack for toolstash -cmp.
|
||||
}
|
||||
if !IsExported(name) && mode != fmtTypeIDName {
|
||||
if !IsExported(name) && mode != fmtTypeIDName && mode != fmtTypeIDHash {
|
||||
name = sconv(s, 0, mode) // qualify non-exported names (used on structs, not on funarg)
|
||||
}
|
||||
} else {
|
||||
@@ -756,7 +768,7 @@ func FmtConst(v constant.Value, sharp bool) string {
|
||||
|
||||
// TypeHash computes a hash value for type t to use in type switch statements.
|
||||
func TypeHash(t *Type) uint32 {
|
||||
p := t.NameString()
|
||||
p := tconv(t, 0, fmtTypeIDHash)
|
||||
|
||||
// Using MD5 is overkill, but reduces accidental collisions.
|
||||
h := md5.Sum([]byte(p))
|
||||
|
||||
@@ -204,12 +204,12 @@ type Info struct {
|
||||
// qualified identifiers are collected in the Uses map.
|
||||
Types map[syntax.Expr]TypeAndValue
|
||||
|
||||
// Instances maps identifiers denoting parameterized types or functions to
|
||||
// their type arguments and instantiated type.
|
||||
// Instances maps identifiers denoting generic types or functions to their
|
||||
// type arguments and instantiated type.
|
||||
//
|
||||
// For example, Instances will map the identifier for 'T' in the type
|
||||
// instantiation T[int, string] to the type arguments [int, string] and
|
||||
// resulting instantiated *Named type. Given a parameterized function
|
||||
// resulting instantiated *Named type. Given a generic function
|
||||
// func F[A any](A), Instances will map the identifier for 'F' in the call
|
||||
// expression F(int(1)) to the inferred type arguments [int], and resulting
|
||||
// instantiated *Signature.
|
||||
@@ -421,8 +421,11 @@ func (conf *Config) Check(path string, files []*syntax.File, info *Info) (*Packa
|
||||
}
|
||||
|
||||
// AssertableTo reports whether a value of type V can be asserted to have type T.
|
||||
// The behavior of AssertableTo is undefined if V is a generalized interface; i.e.,
|
||||
// an interface that may only be used as a type constraint in Go code.
|
||||
//
|
||||
// The behavior of AssertableTo is undefined in two cases:
|
||||
// - if V is a generalized interface; i.e., an interface that may only be used
|
||||
// as a type constraint in Go code
|
||||
// - if T is an uninstantiated generic type
|
||||
func AssertableTo(V *Interface, T Type) bool {
|
||||
// Checker.newAssertableTo suppresses errors for invalid types, so we need special
|
||||
// handling here.
|
||||
@@ -432,20 +435,31 @@ func AssertableTo(V *Interface, T Type) bool {
|
||||
return (*Checker)(nil).newAssertableTo(V, T) == nil
|
||||
}
|
||||
|
||||
// AssignableTo reports whether a value of type V is assignable to a variable of type T.
|
||||
// AssignableTo reports whether a value of type V is assignable to a variable
|
||||
// of type T.
|
||||
//
|
||||
// The behavior of AssignableTo is undefined if V or T is an uninstantiated
|
||||
// generic type.
|
||||
func AssignableTo(V, T Type) bool {
|
||||
x := operand{mode: value, typ: V}
|
||||
ok, _ := x.assignableTo(nil, T, nil) // check not needed for non-constant x
|
||||
return ok
|
||||
}
|
||||
|
||||
// ConvertibleTo reports whether a value of type V is convertible to a value of type T.
|
||||
// ConvertibleTo reports whether a value of type V is convertible to a value of
|
||||
// type T.
|
||||
//
|
||||
// The behavior of ConvertibleTo is undefined if V or T is an uninstantiated
|
||||
// generic type.
|
||||
func ConvertibleTo(V, T Type) bool {
|
||||
x := operand{mode: value, typ: V}
|
||||
return x.convertibleTo(nil, T, nil) // check not needed for non-constant x
|
||||
}
|
||||
|
||||
// Implements reports whether type V implements interface T.
|
||||
//
|
||||
// The behavior of Implements is undefined if V is an uninstantiated generic
|
||||
// type.
|
||||
func Implements(V Type, T *Interface) bool {
|
||||
if T.Empty() {
|
||||
// All types (even Typ[Invalid]) implement the empty interface.
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"internal/testenv"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -403,69 +404,61 @@ func TestTypesInfo(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInstanceInfo(t *testing.T) {
|
||||
var tests = []struct {
|
||||
src string
|
||||
const lib = `package lib
|
||||
|
||||
func F[P any](P) {}
|
||||
|
||||
type T[P any] []P
|
||||
`
|
||||
|
||||
type testInst struct {
|
||||
name string
|
||||
targs []string
|
||||
typ string
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
src string
|
||||
instances []testInst // recorded instances in source order
|
||||
}{
|
||||
{`package p0; func f[T any](T) {}; func _() { f(42) }`,
|
||||
`f`,
|
||||
[]string{`int`},
|
||||
`func(int)`,
|
||||
[]testInst{{`f`, []string{`int`}, `func(int)`}},
|
||||
},
|
||||
{`package p1; func f[T any](T) T { panic(0) }; func _() { f('@') }`,
|
||||
`f`,
|
||||
[]string{`rune`},
|
||||
`func(rune) rune`,
|
||||
[]testInst{{`f`, []string{`rune`}, `func(rune) rune`}},
|
||||
},
|
||||
{`package p2; func f[T any](...T) T { panic(0) }; func _() { f(0i) }`,
|
||||
`f`,
|
||||
[]string{`complex128`},
|
||||
`func(...complex128) complex128`,
|
||||
[]testInst{{`f`, []string{`complex128`}, `func(...complex128) complex128`}},
|
||||
},
|
||||
{`package p3; func f[A, B, C any](A, *B, []C) {}; func _() { f(1.2, new(string), []byte{}) }`,
|
||||
`f`,
|
||||
[]string{`float64`, `string`, `byte`},
|
||||
`func(float64, *string, []byte)`,
|
||||
[]testInst{{`f`, []string{`float64`, `string`, `byte`}, `func(float64, *string, []byte)`}},
|
||||
},
|
||||
{`package p4; func f[A, B any](A, *B, ...[]B) {}; func _() { f(1.2, new(byte)) }`,
|
||||
`f`,
|
||||
[]string{`float64`, `byte`},
|
||||
`func(float64, *byte, ...[]byte)`,
|
||||
[]testInst{{`f`, []string{`float64`, `byte`}, `func(float64, *byte, ...[]byte)`}},
|
||||
},
|
||||
|
||||
// we don't know how to translate these but we can type-check them
|
||||
{`package q0; type T struct{}; func (T) m[P any](P) {}; func _(x T) { x.m(42) }`,
|
||||
`m`,
|
||||
[]string{`int`},
|
||||
`func(int)`,
|
||||
[]testInst{{`m`, []string{`int`}, `func(int)`}},
|
||||
},
|
||||
{`package q1; type T struct{}; func (T) m[P any](P) P { panic(0) }; func _(x T) { x.m(42) }`,
|
||||
`m`,
|
||||
[]string{`int`},
|
||||
`func(int) int`,
|
||||
[]testInst{{`m`, []string{`int`}, `func(int) int`}},
|
||||
},
|
||||
{`package q2; type T struct{}; func (T) m[P any](...P) P { panic(0) }; func _(x T) { x.m(42) }`,
|
||||
`m`,
|
||||
[]string{`int`},
|
||||
`func(...int) int`,
|
||||
[]testInst{{`m`, []string{`int`}, `func(...int) int`}},
|
||||
},
|
||||
{`package q3; type T struct{}; func (T) m[A, B, C any](A, *B, []C) {}; func _(x T) { x.m(1.2, new(string), []byte{}) }`,
|
||||
`m`,
|
||||
[]string{`float64`, `string`, `byte`},
|
||||
`func(float64, *string, []byte)`,
|
||||
[]testInst{{`m`, []string{`float64`, `string`, `byte`}, `func(float64, *string, []byte)`}},
|
||||
},
|
||||
{`package q4; type T struct{}; func (T) m[A, B any](A, *B, ...[]B) {}; func _(x T) { x.m(1.2, new(byte)) }`,
|
||||
`m`,
|
||||
[]string{`float64`, `byte`},
|
||||
`func(float64, *byte, ...[]byte)`,
|
||||
[]testInst{{`m`, []string{`float64`, `byte`}, `func(float64, *byte, ...[]byte)`}},
|
||||
},
|
||||
|
||||
{`package r0; type T[P any] struct{}; func (_ T[P]) m[Q any](Q) {}; func _[P any](x T[P]) { x.m(42) }`,
|
||||
`m`,
|
||||
[]string{`int`},
|
||||
`func(int)`,
|
||||
{`package r0; type T[P1 any] struct{}; func (_ T[P2]) m[Q any](Q) {}; func _[P3 any](x T[P3]) { x.m(42) }`,
|
||||
[]testInst{
|
||||
{`T`, []string{`P2`}, `struct{}`},
|
||||
{`T`, []string{`P3`}, `struct{}`},
|
||||
{`m`, []string{`int`}, `func(int)`},
|
||||
},
|
||||
},
|
||||
// TODO(gri) record method type parameters in syntax.FuncType so we can check this
|
||||
// {`package r1; type T interface{ m[P any](P) }; func _(x T) { x.m(4.2) }`,
|
||||
@@ -474,97 +467,113 @@ func TestInstanceInfo(t *testing.T) {
|
||||
// `func(float64)`,
|
||||
// },
|
||||
|
||||
{`package s1; func f[T any, P interface{~*T}](x T) {}; func _(x string) { f(x) }`,
|
||||
`f`,
|
||||
[]string{`string`, `*string`},
|
||||
`func(x string)`,
|
||||
{`package s1; func f[T any, P interface{*T}](x T) {}; func _(x string) { f(x) }`,
|
||||
[]testInst{{`f`, []string{`string`, `*string`}, `func(x string)`}},
|
||||
},
|
||||
{`package s2; func f[T any, P interface{~*T}](x []T) {}; func _(x []int) { f(x) }`,
|
||||
`f`,
|
||||
[]string{`int`, `*int`},
|
||||
`func(x []int)`,
|
||||
{`package s2; func f[T any, P interface{*T}](x []T) {}; func _(x []int) { f(x) }`,
|
||||
[]testInst{{`f`, []string{`int`, `*int`}, `func(x []int)`}},
|
||||
},
|
||||
{`package s3; type C[T any] interface{~chan<- T}; func f[T any, P C[T]](x []T) {}; func _(x []int) { f(x) }`,
|
||||
`f`,
|
||||
[]string{`int`, `chan<- int`},
|
||||
`func(x []int)`,
|
||||
{`package s3; type C[T any] interface{chan<- T}; func f[T any, P C[T]](x []T) {}; func _(x []int) { f(x) }`,
|
||||
[]testInst{
|
||||
{`C`, []string{`T`}, `interface{chan<- T}`},
|
||||
{`f`, []string{`int`, `chan<- int`}, `func(x []int)`},
|
||||
},
|
||||
},
|
||||
{`package s4; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T) {}; func _(x []int) { f(x) }`,
|
||||
`f`,
|
||||
[]string{`int`, `chan<- int`, `chan<- []*chan<- int`},
|
||||
`func(x []int)`,
|
||||
{`package s4; type C[T any] interface{chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T) {}; func _(x []int) { f(x) }`,
|
||||
[]testInst{
|
||||
{`C`, []string{`T`}, `interface{chan<- T}`},
|
||||
{`C`, []string{`[]*P`}, `interface{chan<- []*P}`},
|
||||
{`f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func(x []int)`},
|
||||
},
|
||||
},
|
||||
|
||||
{`package t1; func f[T any, P interface{~*T}]() T { panic(0) }; func _() { _ = f[string] }`,
|
||||
`f`,
|
||||
[]string{`string`, `*string`},
|
||||
`func() string`,
|
||||
{`package t1; func f[T any, P interface{*T}]() T { panic(0) }; func _() { _ = f[string] }`,
|
||||
[]testInst{{`f`, []string{`string`, `*string`}, `func() string`}},
|
||||
},
|
||||
{`package t2; func f[T any, P interface{~*T}]() T { panic(0) }; func _() { _ = (f[string]) }`,
|
||||
`f`,
|
||||
[]string{`string`, `*string`},
|
||||
`func() string`,
|
||||
{`package t2; func f[T any, P interface{*T}]() T { panic(0) }; func _() { _ = (f[string]) }`,
|
||||
[]testInst{{`f`, []string{`string`, `*string`}, `func() string`}},
|
||||
},
|
||||
{`package t3; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = f[int] }`,
|
||||
`f`,
|
||||
[]string{`int`, `chan<- int`, `chan<- []*chan<- int`},
|
||||
`func() []int`,
|
||||
{`package t3; type C[T any] interface{chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = f[int] }`,
|
||||
[]testInst{
|
||||
{`C`, []string{`T`}, `interface{chan<- T}`},
|
||||
{`C`, []string{`[]*P`}, `interface{chan<- []*P}`},
|
||||
{`f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func() []int`},
|
||||
},
|
||||
},
|
||||
{`package t4; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = f[int] }`,
|
||||
`f`,
|
||||
[]string{`int`, `chan<- int`, `chan<- []*chan<- int`},
|
||||
`func() []int`,
|
||||
{`package t4; type C[T any] interface{chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = (f[int]) }`,
|
||||
[]testInst{
|
||||
{`C`, []string{`T`}, `interface{chan<- T}`},
|
||||
{`C`, []string{`[]*P`}, `interface{chan<- []*P}`},
|
||||
{`f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func() []int`},
|
||||
},
|
||||
},
|
||||
{`package i0; import lib "generic_lib"; func _() { lib.F(42) }`,
|
||||
`F`,
|
||||
[]string{`int`},
|
||||
`func(int)`,
|
||||
{`package i0; import "lib"; func _() { lib.F(42) }`,
|
||||
[]testInst{{`F`, []string{`int`}, `func(int)`}},
|
||||
},
|
||||
|
||||
{`package duplfunc0; func f[T any](T) {}; func _() { f(42); f("foo"); f[int](3) }`,
|
||||
[]testInst{
|
||||
{`f`, []string{`int`}, `func(int)`},
|
||||
{`f`, []string{`string`}, `func(string)`},
|
||||
{`f`, []string{`int`}, `func(int)`},
|
||||
},
|
||||
},
|
||||
{`package duplfunc1; import "lib"; func _() { lib.F(42); lib.F("foo"); lib.F(3) }`,
|
||||
[]testInst{
|
||||
{`F`, []string{`int`}, `func(int)`},
|
||||
{`F`, []string{`string`}, `func(string)`},
|
||||
{`F`, []string{`int`}, `func(int)`},
|
||||
},
|
||||
},
|
||||
|
||||
{`package type0; type T[P interface{~int}] struct{ x P }; var _ T[int]`,
|
||||
`T`,
|
||||
[]string{`int`},
|
||||
`struct{x int}`,
|
||||
[]testInst{{`T`, []string{`int`}, `struct{x int}`}},
|
||||
},
|
||||
{`package type1; type T[P interface{~int}] struct{ x P }; var _ (T[int])`,
|
||||
`T`,
|
||||
[]string{`int`},
|
||||
`struct{x int}`,
|
||||
[]testInst{{`T`, []string{`int`}, `struct{x int}`}},
|
||||
},
|
||||
{`package type2; type T[P interface{~int}] struct{ x P }; var _ T[(int)]`,
|
||||
`T`,
|
||||
[]string{`int`},
|
||||
`struct{x int}`,
|
||||
[]testInst{{`T`, []string{`int`}, `struct{x int}`}},
|
||||
},
|
||||
{`package type3; type T[P1 interface{~[]P2}, P2 any] struct{ x P1; y P2 }; var _ T[[]int, int]`,
|
||||
`T`,
|
||||
[]string{`[]int`, `int`},
|
||||
`struct{x []int; y int}`,
|
||||
[]testInst{{`T`, []string{`[]int`, `int`}, `struct{x []int; y int}`}},
|
||||
},
|
||||
{`package type4; import lib "generic_lib"; var _ lib.T[int]`,
|
||||
`T`,
|
||||
[]string{`int`},
|
||||
`[]int`,
|
||||
{`package type4; import "lib"; var _ lib.T[int]`,
|
||||
[]testInst{{`T`, []string{`int`}, `[]int`}},
|
||||
},
|
||||
|
||||
{`package dupltype0; type T[P interface{~int}] struct{ x P }; var x T[int]; var y T[int]`,
|
||||
[]testInst{
|
||||
{`T`, []string{`int`}, `struct{x int}`},
|
||||
{`T`, []string{`int`}, `struct{x int}`},
|
||||
},
|
||||
},
|
||||
{`package dupltype1; type T[P ~int] struct{ x P }; func (r *T[Q]) add(z T[Q]) { r.x += z.x }`,
|
||||
[]testInst{
|
||||
{`T`, []string{`Q`}, `struct{x Q}`},
|
||||
{`T`, []string{`Q`}, `struct{x Q}`},
|
||||
},
|
||||
},
|
||||
{`package dupltype1; import "lib"; var x lib.T[int]; var y lib.T[int]; var z lib.T[string]`,
|
||||
[]testInst{
|
||||
{`T`, []string{`int`}, `[]int`},
|
||||
{`T`, []string{`int`}, `[]int`},
|
||||
{`T`, []string{`string`}, `[]string`},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
const lib = `package generic_lib
|
||||
|
||||
func F[P any](P) {}
|
||||
|
||||
type T[P any] []P
|
||||
`
|
||||
|
||||
imports := make(testImporter)
|
||||
conf := Config{Importer: imports}
|
||||
instances := make(map[*syntax.Name]Instance)
|
||||
uses := make(map[*syntax.Name]Object)
|
||||
instMap := make(map[*syntax.Name]Instance)
|
||||
useMap := make(map[*syntax.Name]Object)
|
||||
makePkg := func(src string) *Package {
|
||||
f, err := parseSrc("p.go", src)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pkg, err := conf.Check("", []*syntax.File{f}, &Info{Instances: instances, Uses: uses})
|
||||
pkg, err := conf.Check("", []*syntax.File{f}, &Info{Instances: instMap, Uses: useMap})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -574,60 +583,72 @@ type T[P any] []P
|
||||
makePkg(lib)
|
||||
pkg := makePkg(test.src)
|
||||
|
||||
// look for instance information
|
||||
var targs []Type
|
||||
var typ Type
|
||||
for ident, inst := range instances {
|
||||
if syntax.String(ident) == test.name {
|
||||
for i := 0; i < inst.TypeArgs.Len(); i++ {
|
||||
targs = append(targs, inst.TypeArgs.At(i))
|
||||
}
|
||||
typ = inst.Type
|
||||
t.Run(pkg.Name(), func(t *testing.T) {
|
||||
// Sort instances in source order for stability.
|
||||
instances := sortedInstances(instMap)
|
||||
if got, want := len(instances), len(test.instances); got != want {
|
||||
t.Fatalf("got %d instances, want %d", got, want)
|
||||
}
|
||||
|
||||
// Check that we can find the corresponding parameterized type.
|
||||
ptype := uses[ident].Type()
|
||||
// Pairwise compare with the expected instances.
|
||||
for ii, inst := range instances {
|
||||
var targs []Type
|
||||
for i := 0; i < inst.Inst.TypeArgs.Len(); i++ {
|
||||
targs = append(targs, inst.Inst.TypeArgs.At(i))
|
||||
}
|
||||
typ := inst.Inst.Type
|
||||
|
||||
testInst := test.instances[ii]
|
||||
if got := inst.Name.Value; got != testInst.name {
|
||||
t.Fatalf("got name %s, want %s", got, testInst.name)
|
||||
}
|
||||
|
||||
if len(targs) != len(testInst.targs) {
|
||||
t.Fatalf("got %d type arguments; want %d", len(targs), len(testInst.targs))
|
||||
}
|
||||
for i, targ := range targs {
|
||||
if got := targ.String(); got != testInst.targs[i] {
|
||||
t.Errorf("type argument %d: got %s; want %s", i, got, testInst.targs[i])
|
||||
}
|
||||
}
|
||||
if got := typ.Underlying().String(); got != testInst.typ {
|
||||
t.Errorf("package %s: got %s; want %s", pkg.Name(), got, testInst.typ)
|
||||
}
|
||||
|
||||
// Verify the invariant that re-instantiating the corresponding generic
|
||||
// type with TypeArgs results in an identical instance.
|
||||
ptype := useMap[inst.Name].Type()
|
||||
lister, _ := ptype.(interface{ TypeParams() *TypeParamList })
|
||||
if lister == nil || lister.TypeParams().Len() == 0 {
|
||||
t.Errorf("package %s: info.Types[%v] = %v, want parameterized type", pkg.Name(), ident, ptype)
|
||||
continue
|
||||
t.Fatalf("info.Types[%v] = %v, want parameterized type", inst.Name, ptype)
|
||||
}
|
||||
|
||||
// Verify the invariant that re-instantiating the generic type with
|
||||
// TypeArgs results in an equivalent type.
|
||||
inst2, err := Instantiate(nil, ptype, targs, true)
|
||||
if err != nil {
|
||||
t.Errorf("Instantiate(%v, %v) failed: %v", ptype, targs, err)
|
||||
}
|
||||
if !Identical(inst.Type, inst2) {
|
||||
t.Errorf("%v and %v are not identical", inst.Type, inst2)
|
||||
if !Identical(inst.Inst.Type, inst2) {
|
||||
t.Errorf("%v and %v are not identical", inst.Inst.Type, inst2)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if targs == nil {
|
||||
t.Errorf("package %s: no instance information found for %s", pkg.Name(), test.name)
|
||||
continue
|
||||
}
|
||||
|
||||
// check that type arguments are correct
|
||||
if len(targs) != len(test.targs) {
|
||||
t.Errorf("package %s: got %d type arguments; want %d", pkg.Name(), len(targs), len(test.targs))
|
||||
continue
|
||||
}
|
||||
for i, targ := range targs {
|
||||
if got := targ.String(); got != test.targs[i] {
|
||||
t.Errorf("package %s, %d. type argument: got %s; want %s", pkg.Name(), i, got, test.targs[i])
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// check that the types match
|
||||
if got := typ.Underlying().String(); got != test.typ {
|
||||
t.Errorf("package %s: got %s; want %s", pkg.Name(), got, test.typ)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type recordedInstance struct {
|
||||
Name *syntax.Name
|
||||
Inst Instance
|
||||
}
|
||||
|
||||
func sortedInstances(m map[*syntax.Name]Instance) (instances []recordedInstance) {
|
||||
for id, inst := range m {
|
||||
instances = append(instances, recordedInstance{id, inst})
|
||||
}
|
||||
sort.Slice(instances, func(i, j int) bool {
|
||||
return instances[i].Name.Pos().Cmp(instances[j].Name.Pos()) < 0
|
||||
})
|
||||
return instances
|
||||
}
|
||||
|
||||
func TestDefsInfo(t *testing.T) {
|
||||
var tests = []struct {
|
||||
src string
|
||||
@@ -1697,7 +1718,7 @@ func F(){
|
||||
var F = /*F=func:12*/ F /*F=var:17*/ ; _ = F
|
||||
|
||||
var a []int
|
||||
for i, x := range /*i=undef*/ /*x=var:16*/ a /*i=var:20*/ /*x=var:20*/ { _ = i; _ = x }
|
||||
for i, x := range a /*i=undef*/ /*x=var:16*/ { _ = i; _ = x }
|
||||
|
||||
var i interface{}
|
||||
switch y := i.(type) { /*y=undef*/
|
||||
|
||||
@@ -423,7 +423,7 @@ var cgoPrefixes = [...]string{
|
||||
"_Cmacro_", // function to evaluate the expanded expression
|
||||
}
|
||||
|
||||
func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) {
|
||||
func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *Named) {
|
||||
// these must be declared before the "goto Error" statements
|
||||
var (
|
||||
obj Object
|
||||
@@ -526,6 +526,12 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) {
|
||||
|
||||
check.exprOrType(x, e.X, false)
|
||||
switch x.mode {
|
||||
case typexpr:
|
||||
// don't crash for "type T T.x" (was issue #51509)
|
||||
if def != nil && x.typ == def {
|
||||
check.cycleError([]Object{def.obj})
|
||||
goto Error
|
||||
}
|
||||
case builtin:
|
||||
check.errorf(e.Pos(), "cannot select on %s", x)
|
||||
goto Error
|
||||
|
||||
@@ -1556,7 +1556,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
|
||||
return kind
|
||||
|
||||
case *syntax.SelectorExpr:
|
||||
check.selector(x, e)
|
||||
check.selector(x, e, nil)
|
||||
|
||||
case *syntax.IndexExpr:
|
||||
if check.indexExpr(x, e) {
|
||||
@@ -1642,6 +1642,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
|
||||
case invalid:
|
||||
goto Error
|
||||
case typexpr:
|
||||
check.validVarType(e.X, x.typ)
|
||||
x.typ = &Pointer{base: x.typ}
|
||||
default:
|
||||
var base Type
|
||||
|
||||
@@ -488,21 +488,88 @@ func (check *Checker) inferB(pos syntax.Pos, tparams []*TypeParam, targs []Type)
|
||||
}
|
||||
}
|
||||
|
||||
// If a constraint has a core type, unify the corresponding type parameter with it.
|
||||
for _, tpar := range tparams {
|
||||
if ctype := adjCoreType(tpar); ctype != nil {
|
||||
if !u.unify(tpar, ctype) {
|
||||
// TODO(gri) improve error message by providing the type arguments
|
||||
// which we know already
|
||||
check.errorf(pos, "%s does not match %s", tpar, ctype)
|
||||
return nil, 0
|
||||
// Repeatedly apply constraint type inference as long as
|
||||
// there are still unknown type arguments and progress is
|
||||
// being made.
|
||||
//
|
||||
// This is an O(n^2) algorithm where n is the number of
|
||||
// type parameters: if there is progress (and iteration
|
||||
// continues), at least one type argument is inferred
|
||||
// per iteration and we have a doubly nested loop.
|
||||
// In practice this is not a problem because the number
|
||||
// of type parameters tends to be very small (< 5 or so).
|
||||
// (It should be possible for unification to efficiently
|
||||
// signal newly inferred type arguments; then the loops
|
||||
// here could handle the respective type parameters only,
|
||||
// but that will come at a cost of extra complexity which
|
||||
// may not be worth it.)
|
||||
for n := u.x.unknowns(); n > 0; {
|
||||
nn := n
|
||||
|
||||
for i, tpar := range tparams {
|
||||
// If there is a core term (i.e., a core type with tilde information)
|
||||
// unify the type parameter with the core type.
|
||||
if core, single := coreTerm(tpar); core != nil {
|
||||
// A type parameter can be unified with its core type in two cases.
|
||||
tx := u.x.at(i)
|
||||
switch {
|
||||
case tx != nil:
|
||||
// The corresponding type argument tx is known.
|
||||
// In this case, if the core type has a tilde, the type argument's underlying
|
||||
// type must match the core type, otherwise the type argument and the core type
|
||||
// must match.
|
||||
// If tx is an external type parameter, don't consider its underlying type
|
||||
// (which is an interface). Core type unification will attempt to unify against
|
||||
// core.typ.
|
||||
// Note also that even with inexact unification we cannot leave away the under
|
||||
// call here because it's possible that both tx and core.typ are named types,
|
||||
// with under(tx) being a (named) basic type matching core.typ. Such cases do
|
||||
// not match with inexact unification.
|
||||
if core.tilde && !isTypeParam(tx) {
|
||||
tx = under(tx)
|
||||
}
|
||||
if !u.unify(tx, core.typ) {
|
||||
// TODO(gri) improve error message by providing the type arguments
|
||||
// which we know already
|
||||
// Don't use term.String() as it always qualifies types, even if they
|
||||
// are in the current package.
|
||||
tilde := ""
|
||||
if core.tilde {
|
||||
tilde = "~"
|
||||
}
|
||||
check.errorf(pos, "%s does not match %s%s", tpar, tilde, core.typ)
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
case single && !core.tilde:
|
||||
// The corresponding type argument tx is unknown and there's a single
|
||||
// specific type and no tilde.
|
||||
// In this case the type argument must be that single type; set it.
|
||||
u.x.set(i, core.typ)
|
||||
|
||||
default:
|
||||
// Unification is not possible and no progress was made.
|
||||
continue
|
||||
}
|
||||
|
||||
// The number of known type arguments may have changed.
|
||||
nn = u.x.unknowns()
|
||||
if nn == 0 {
|
||||
break // all type arguments are known
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(nn <= n)
|
||||
if nn == n {
|
||||
break // no progress
|
||||
}
|
||||
n = nn
|
||||
}
|
||||
|
||||
// u.x.types() now contains the incoming type arguments plus any additional type
|
||||
// arguments which were inferred from core types. The newly inferred non-
|
||||
// nil entries may still contain references to other type parameters.
|
||||
// arguments which were inferred from core terms. The newly inferred non-nil
|
||||
// entries may still contain references to other type parameters.
|
||||
// For instance, for [A any, B interface{ []C }, C interface{ *A }], if A == int
|
||||
// was given, unification produced the type list [int, []C, *A]. We eliminate the
|
||||
// remaining type parameters by substituting the type parameters in this type list
|
||||
@@ -591,26 +658,40 @@ func (check *Checker) inferB(pos syntax.Pos, tparams []*TypeParam, targs []Type)
|
||||
return
|
||||
}
|
||||
|
||||
// adjCoreType returns the core type of tpar unless the
|
||||
// type parameter embeds a single, possibly named type,
|
||||
// in which case it returns that single type instead.
|
||||
// (The core type is always the underlying type of that
|
||||
// single type.)
|
||||
func adjCoreType(tpar *TypeParam) Type {
|
||||
var single *term
|
||||
if tpar.is(func(t *term) bool {
|
||||
if single == nil && t != nil {
|
||||
single = t
|
||||
return true
|
||||
// If the type parameter has a single specific type S, coreTerm returns (S, true).
|
||||
// Otherwise, if tpar has a core type T, it returns a term corresponding to that
|
||||
// core type and false. In that case, if any term of tpar has a tilde, the core
|
||||
// term has a tilde. In all other cases coreTerm returns (nil, false).
|
||||
func coreTerm(tpar *TypeParam) (*term, bool) {
|
||||
n := 0
|
||||
var single *term // valid if n == 1
|
||||
var tilde bool
|
||||
tpar.is(func(t *term) bool {
|
||||
if t == nil {
|
||||
assert(n == 0)
|
||||
return false // no terms
|
||||
}
|
||||
return false // zero or more than one terms
|
||||
}) {
|
||||
n++
|
||||
single = t
|
||||
if t.tilde {
|
||||
tilde = true
|
||||
}
|
||||
return true
|
||||
})
|
||||
if n == 1 {
|
||||
if debug {
|
||||
assert(under(single.typ) == coreType(tpar))
|
||||
assert(debug && under(single.typ) == coreType(tpar))
|
||||
}
|
||||
return single.typ
|
||||
return single, true
|
||||
}
|
||||
return coreType(tpar)
|
||||
if typ := coreType(tpar); typ != nil {
|
||||
// A core type is always an underlying type.
|
||||
// If any term of tpar has a tilde, we don't
|
||||
// have a precise core type and we must return
|
||||
// a tilde as well.
|
||||
return &term{tilde, typ}, false
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
type cycleFinder struct {
|
||||
@@ -658,8 +739,6 @@ func (w *cycleFinder) typ(typ Type) {
|
||||
// in signatures where they are handled explicitly.
|
||||
|
||||
case *Signature:
|
||||
// There are no "method types" so we should never see a recv.
|
||||
assert(t.recv == nil)
|
||||
if t.params != nil {
|
||||
w.varList(t.params.vars)
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@ import (
|
||||
|
||||
// Instantiate instantiates the type orig with the given type arguments targs.
|
||||
// orig must be a *Named or a *Signature type. If there is no error, the
|
||||
// resulting Type is a new, instantiated (not parameterized) type of the same
|
||||
// kind (either a *Named or a *Signature). Methods attached to a *Named type
|
||||
// are also instantiated, and associated with a new *Func that has the same
|
||||
// position as the original method, but nil function scope.
|
||||
// resulting Type is an instantiated type of the same kind (either a *Named or
|
||||
// a *Signature). Methods attached to a *Named type are also instantiated, and
|
||||
// associated with a new *Func that has the same position as the original
|
||||
// method, but nil function scope.
|
||||
//
|
||||
// If ctxt is non-nil, it may be used to de-duplicate the instance against
|
||||
// previous instances with the same identity. As a special case, generic
|
||||
|
||||
@@ -70,7 +70,8 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
|
||||
// see if there is a matching field (but not a method, those need to be declared
|
||||
// explicitly in the constraint). If the constraint is a named pointer type (see
|
||||
// above), we are ok here because only fields are accepted as results.
|
||||
if obj == nil && isTypeParam(T) {
|
||||
const enableTParamFieldLookup = false // see issue #51576
|
||||
if enableTParamFieldLookup && obj == nil && isTypeParam(T) {
|
||||
if t := coreType(T); t != nil {
|
||||
obj, index, indirect = lookupFieldOrMethod(t, addressable, pkg, name, false)
|
||||
if _, ok := obj.(*Var); !ok {
|
||||
|
||||
@@ -98,10 +98,10 @@ func (t *Named) cleanup() {
|
||||
}
|
||||
|
||||
// Obj returns the type name for the declaration defining the named type t. For
|
||||
// instantiated types, this is the type name of the base type.
|
||||
// instantiated types, this is same as the type name of the origin type.
|
||||
func (t *Named) Obj() *TypeName { return t.orig.obj } // for non-instances this is the same as t.obj
|
||||
|
||||
// Origin returns the parameterized type from which the named type t is
|
||||
// Origin returns the generic type from which the named type t is
|
||||
// instantiated. If t is not an instantiated type, the result is t.
|
||||
func (t *Named) Origin() *Named { return t.orig }
|
||||
|
||||
@@ -109,7 +109,7 @@ func (t *Named) Origin() *Named { return t.orig }
|
||||
// between parameterized instantiated and non-instantiated types.
|
||||
|
||||
// TypeParams returns the type parameters of the named type t, or nil.
|
||||
// The result is non-nil for an (originally) parameterized type even if it is instantiated.
|
||||
// The result is non-nil for an (originally) generic type even if it is instantiated.
|
||||
func (t *Named) TypeParams() *TypeParamList { return t.resolve(nil).tparams }
|
||||
|
||||
// SetTypeParams sets the type parameters of the named type t.
|
||||
@@ -122,7 +122,11 @@ func (t *Named) SetTypeParams(tparams []*TypeParam) {
|
||||
// TypeArgs returns the type arguments used to instantiate the named type t.
|
||||
func (t *Named) TypeArgs() *TypeList { return t.targs }
|
||||
|
||||
// NumMethods returns the number of explicit methods whose receiver is named type t.
|
||||
// NumMethods returns the number of explicit methods defined for t.
|
||||
//
|
||||
// For an ordinary or instantiated type t, the receiver base type of these
|
||||
// methods will be the named type t. For an uninstantiated generic type t, each
|
||||
// method receiver will be instantiated with its receiver type parameters.
|
||||
func (t *Named) NumMethods() int { return t.resolve(nil).methods.Len() }
|
||||
|
||||
// Method returns the i'th method of named type t for 0 <= i < t.NumMethods().
|
||||
|
||||
@@ -413,7 +413,7 @@ func (check *Checker) collectObjects() {
|
||||
|
||||
case *syntax.TypeDecl:
|
||||
if len(s.TParamList) != 0 && !check.allowVersion(pkg, 1, 18) {
|
||||
check.softErrorf(s.TParamList[0], "type parameters require go1.18 or later")
|
||||
check.versionErrorf(s.TParamList[0], "go1.18", "type parameter")
|
||||
}
|
||||
obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Value, nil)
|
||||
check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, tdecl: s})
|
||||
@@ -458,7 +458,7 @@ func (check *Checker) collectObjects() {
|
||||
check.recordDef(s.Name, obj)
|
||||
}
|
||||
if len(s.TParamList) != 0 && !check.allowVersion(pkg, 1, 18) && !hasTParamError {
|
||||
check.softErrorf(s.TParamList[0], "type parameters require go1.18 or later")
|
||||
check.versionErrorf(s.TParamList[0], "go1.18", "type parameter")
|
||||
}
|
||||
info := &declInfo{file: fileScope, fdecl: s}
|
||||
// Methods are not package-level objects but we still track them in the
|
||||
|
||||
@@ -626,14 +626,15 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
|
||||
|
||||
case *syntax.ForStmt:
|
||||
inner |= breakOk | continueOk
|
||||
check.openScope(s, "for")
|
||||
defer check.closeScope()
|
||||
|
||||
if rclause, _ := s.Init.(*syntax.RangeClause); rclause != nil {
|
||||
check.rangeStmt(inner, s, rclause)
|
||||
break
|
||||
}
|
||||
|
||||
check.openScope(s, "for")
|
||||
defer check.closeScope()
|
||||
|
||||
check.simpleStmt(s.Init)
|
||||
if s.Cond != nil {
|
||||
var x operand
|
||||
@@ -809,8 +810,6 @@ func (check *Checker) typeSwitchStmt(inner stmtContext, s *syntax.SwitchStmt, gu
|
||||
}
|
||||
|
||||
func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *syntax.RangeClause) {
|
||||
// scope already opened
|
||||
|
||||
// determine lhs, if any
|
||||
sKey := rclause.Lhs // possibly nil
|
||||
var sValue, sExtra syntax.Expr
|
||||
@@ -866,6 +865,11 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
|
||||
}
|
||||
}
|
||||
|
||||
// Open the for-statement block scope now, after the range clause.
|
||||
// Iteration variables declared with := need to go in this scope (was issue #51437).
|
||||
check.openScope(s, "range")
|
||||
defer check.closeScope()
|
||||
|
||||
// check assignment to/declaration of iteration variables
|
||||
// (irregular assignment, cannot easily map to existing assignment checks)
|
||||
|
||||
@@ -874,9 +878,7 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
|
||||
rhs := [2]Type{key, val} // key, val may be nil
|
||||
|
||||
if rclause.Def {
|
||||
// short variable declaration; variable scope starts after the range clause
|
||||
// (the for loop opens a new scope, so variables on the lhs never redeclare
|
||||
// previously declared variables)
|
||||
// short variable declaration
|
||||
var vars []*Var
|
||||
for i, lhs := range lhs {
|
||||
if lhs == nil {
|
||||
@@ -913,12 +915,8 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
|
||||
|
||||
// declare variables
|
||||
if len(vars) > 0 {
|
||||
scopePos := syntax.EndPos(rclause.X) // TODO(gri) should this just be s.Body.Pos (spec clarification)?
|
||||
scopePos := s.Body.Pos()
|
||||
for _, obj := range vars {
|
||||
// spec: "The scope of a constant or variable identifier declared inside
|
||||
// a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
|
||||
// for short variable declarations) and ends at the end of the innermost
|
||||
// containing block."
|
||||
check.declare(check.scope, nil /* recordDef already called */, obj, scopePos)
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -8,21 +8,21 @@ import "strconv"
|
||||
|
||||
type any interface{}
|
||||
|
||||
func f0[A any, B interface{~*C}, C interface{~*D}, D interface{~*A}](A, B, C, D) {}
|
||||
func f0[A any, B interface{*C}, C interface{*D}, D interface{*A}](A, B, C, D) {}
|
||||
func _() {
|
||||
f := f0[string]
|
||||
f("a", nil, nil, nil)
|
||||
f0("a", nil, nil, nil)
|
||||
}
|
||||
|
||||
func f1[A any, B interface{~*A}](A, B) {}
|
||||
func f1[A any, B interface{*A}](A, B) {}
|
||||
func _() {
|
||||
f := f1[int]
|
||||
f(int(0), new(int))
|
||||
f1(int(0), new(int))
|
||||
}
|
||||
|
||||
func f2[A any, B interface{~[]A}](A, B) {}
|
||||
func f2[A any, B interface{[]A}](A, B) {}
|
||||
func _() {
|
||||
f := f2[byte]
|
||||
f(byte(0), []byte{})
|
||||
@@ -38,7 +38,7 @@ func _() {
|
||||
// f3(x, &x, &x)
|
||||
// }
|
||||
|
||||
func f4[A any, B interface{~[]C}, C interface{~*A}](A, B, C) {}
|
||||
func f4[A any, B interface{[]C}, C interface{*A}](A, B, C) {}
|
||||
func _() {
|
||||
f := f4[int]
|
||||
var x int
|
||||
@@ -46,7 +46,7 @@ func _() {
|
||||
f4(x, []*int{}, &x)
|
||||
}
|
||||
|
||||
func f5[A interface{~struct{b B; c C}}, B any, C interface{~*B}](x B) A { panic(0) }
|
||||
func f5[A interface{struct{b B; c C}}, B any, C interface{*B}](x B) A { panic(0) }
|
||||
func _() {
|
||||
x := f5(1.2)
|
||||
var _ float64 = x.b
|
||||
@@ -79,14 +79,14 @@ var _ = Double(MySlice{1})
|
||||
|
||||
type Setter[B any] interface {
|
||||
Set(string)
|
||||
~*B
|
||||
*B
|
||||
}
|
||||
|
||||
func FromStrings[T interface{}, PT Setter[T]](s []string) []T {
|
||||
result := make([]T, len(s))
|
||||
for i, v := range s {
|
||||
// The type of &result[i] is *T which is in the type list
|
||||
// of Setter2, so we can convert it to PT.
|
||||
// of Setter, so we can convert it to PT.
|
||||
p := PT(&result[i])
|
||||
// PT has a Set method.
|
||||
p.Set(v)
|
||||
|
||||
@@ -4,44 +4,46 @@
|
||||
|
||||
package typeInference
|
||||
|
||||
// As of issue #51527, type-type inference has been disabled.
|
||||
|
||||
// basic inference
|
||||
type Tb[P ~*Q, Q any] int
|
||||
func _() {
|
||||
var x Tb[*int]
|
||||
var x Tb /* ERROR got 1 arguments */ [*int]
|
||||
var y Tb[*int, int]
|
||||
x = y
|
||||
x = y /* ERROR cannot use y .* in assignment */
|
||||
_ = x
|
||||
}
|
||||
|
||||
// recursive inference
|
||||
type Tr[A any, B ~*C, C ~*D, D ~*A] int
|
||||
type Tr[A any, B *C, C *D, D *A] int
|
||||
func _() {
|
||||
var x Tr[string]
|
||||
var x Tr /* ERROR got 1 arguments */ [string]
|
||||
var y Tr[string, ***string, **string, *string]
|
||||
var z Tr[int, ***int, **int, *int]
|
||||
x = y
|
||||
x = y /* ERROR cannot use y .* in assignment */
|
||||
x = z // ERROR cannot use z .* as Tr
|
||||
_ = x
|
||||
}
|
||||
|
||||
// other patterns of inference
|
||||
type To0[A any, B ~[]A] int
|
||||
type To1[A any, B ~struct{a A}] int
|
||||
type To2[A any, B ~[][]A] int
|
||||
type To3[A any, B ~[3]*A] int
|
||||
type To4[A any, B any, C ~struct{a A; b B}] int
|
||||
type To0[A any, B []A] int
|
||||
type To1[A any, B struct{a A}] int
|
||||
type To2[A any, B [][]A] int
|
||||
type To3[A any, B [3]*A] int
|
||||
type To4[A any, B any, C struct{a A; b B}] int
|
||||
func _() {
|
||||
var _ To0[int]
|
||||
var _ To1[int]
|
||||
var _ To2[int]
|
||||
var _ To3[int]
|
||||
var _ To4[int, string]
|
||||
var _ To0 /* ERROR got 1 arguments */ [int]
|
||||
var _ To1 /* ERROR got 1 arguments */ [int]
|
||||
var _ To2 /* ERROR got 1 arguments */ [int]
|
||||
var _ To3 /* ERROR got 1 arguments */ [int]
|
||||
var _ To4 /* ERROR got 2 arguments */ [int, string]
|
||||
}
|
||||
|
||||
// failed inference
|
||||
type Tf0[A, B any] int
|
||||
type Tf1[A any, B ~struct{a A; c C}, C any] int
|
||||
func _() {
|
||||
var _ Tf0 /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type parameters */ [int]
|
||||
var _ Tf1 /* ERROR cannot infer B */ /* ERROR got 1 arguments but 3 type parameters */ [int]
|
||||
var _ Tf0 /* ERROR got 1 arguments but 2 type parameters */ [int]
|
||||
var _ Tf1 /* ERROR got 1 arguments but 3 type parameters */ [int]
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ func _() {
|
||||
related1(si, "foo" /* ERROR cannot use "foo" */ )
|
||||
}
|
||||
|
||||
func related2[Elem any, Slice interface{~[]Elem}](e Elem, s Slice) {}
|
||||
func related2[Elem any, Slice interface{[]Elem}](e Elem, s Slice) {}
|
||||
|
||||
func _() {
|
||||
// related2 can be called with explicit instantiation.
|
||||
@@ -109,16 +109,8 @@ func _() {
|
||||
related3[int, []int]()
|
||||
related3[byte, List[byte]]()
|
||||
|
||||
// Alternatively, the 2nd type argument can be inferred
|
||||
// from the first one through constraint type inference.
|
||||
related3[int]()
|
||||
|
||||
// The inferred type is the core type of the Slice
|
||||
// type parameter.
|
||||
var _ []int = related3[int]()
|
||||
|
||||
// It is not the defined parameterized type List.
|
||||
type anotherList []float32
|
||||
var _ anotherList = related3[float32]() // valid
|
||||
var _ anotherList = related3 /* ERROR cannot use .* \(value of type List\[float32\]\) as anotherList */ [float32, List[float32]]()
|
||||
// The 2nd type argument cannot be inferred from the first
|
||||
// one because there's two possible choices: []Elem and
|
||||
// List[Elem].
|
||||
related3[int]( /* ERROR cannot infer Slice */ )
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ func _() int {
|
||||
return deref(p)
|
||||
}
|
||||
|
||||
func addrOfCopy[V any, P ~*V](v V) P {
|
||||
func addrOfCopy[V any, P *V](v V) P {
|
||||
return &v
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ type _ struct{
|
||||
}
|
||||
|
||||
type _ struct{
|
||||
I3 // ERROR interface is .* comparable
|
||||
I3 // ERROR interface contains type constraints
|
||||
}
|
||||
|
||||
// General composite types.
|
||||
@@ -59,19 +59,19 @@ type (
|
||||
_ []I1 // ERROR interface is .* comparable
|
||||
_ []I2 // ERROR interface contains type constraints
|
||||
|
||||
_ *I3 // ERROR interface is .* comparable
|
||||
_ *I3 // ERROR interface contains type constraints
|
||||
_ map[I1 /* ERROR interface is .* comparable */ ]I2 // ERROR interface contains type constraints
|
||||
_ chan I3 // ERROR interface is .* comparable
|
||||
_ chan I3 // ERROR interface contains type constraints
|
||||
_ func(I1 /* ERROR interface is .* comparable */ )
|
||||
_ func() I2 // ERROR interface contains type constraints
|
||||
)
|
||||
|
||||
// Other cases.
|
||||
|
||||
var _ = [...]I3 /* ERROR interface is .* comparable */ {}
|
||||
var _ = [...]I3 /* ERROR interface contains type constraints */ {}
|
||||
|
||||
func _(x interface{}) {
|
||||
_ = x.(I3 /* ERROR interface is .* comparable */ )
|
||||
_ = x.(I3 /* ERROR interface contains type constraints */ )
|
||||
}
|
||||
|
||||
type T1[_ any] struct{}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
package p
|
||||
|
||||
func f[F interface{~*Q}, G interface{~*R}, Q, R any](q Q, r R) {}
|
||||
func f[F interface{*Q}, G interface{*R}, Q, R any](q Q, r R) {}
|
||||
|
||||
func _() {
|
||||
f[*float64, *int](1, 2)
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
|
||||
package go1_17
|
||||
|
||||
type T[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ] struct{}
|
||||
type T[P /* ERROR type parameter requires go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ] struct{}
|
||||
|
||||
// for init (and main, but we're not in package main) we should only get one error
|
||||
func init[P /* ERROR func init must have no type parameters */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ]() {}
|
||||
func main[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ]() {}
|
||||
func main[P /* ERROR type parameter requires go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ]() {}
|
||||
|
||||
func f[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ](x P) {
|
||||
func f[P /* ERROR type parameter requires go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ](x P) {
|
||||
var _ T[ /* ERROR type instantiation requires go1\.18 or later */ int]
|
||||
var _ (T[ /* ERROR type instantiation requires go1\.18 or later */ int])
|
||||
_ = T[ /* ERROR type instantiation requires go1\.18 or later */ int]{}
|
||||
|
||||
@@ -10,9 +10,10 @@ type S[A, B any] struct {
|
||||
|
||||
func (S[A, B]) m() {}
|
||||
|
||||
// TODO(gri) We should only report one error below. See issue #50588.
|
||||
// TODO(gri): with type-type inference enabled we should only report one error
|
||||
// below. See issue #50588.
|
||||
|
||||
func _[A any](s S /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type parameters */ [A]) {
|
||||
func _[A any](s S /* ERROR got 1 arguments but 2 type parameters */ [A]) {
|
||||
// we should see no follow-on errors below
|
||||
s.f = 1
|
||||
s.m()
|
||||
@@ -21,7 +22,7 @@ func _[A any](s S /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type
|
||||
// another test case from the issue
|
||||
|
||||
func _() {
|
||||
X(Interface[*F /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type parameters */ [string]](Impl{}))
|
||||
X(Interface[*F /* ERROR got 1 arguments but 2 type parameters */ [string]](Impl{}))
|
||||
}
|
||||
|
||||
func X[Q Qer](fs Interface[Q]) {
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Field accesses through type parameters are disabled
|
||||
// until we have a more thorough understanding of the
|
||||
// implications on the spec. See issue #51576.
|
||||
|
||||
package p
|
||||
|
||||
type Sf struct {
|
||||
@@ -9,13 +13,13 @@ type Sf struct {
|
||||
}
|
||||
|
||||
func f0[P Sf](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
_ = p.f // ERROR p\.f undefined
|
||||
p.f /* ERROR p\.f undefined */ = 0
|
||||
}
|
||||
|
||||
func f0t[P ~struct{f int}](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
_ = p.f // ERROR p\.f undefined
|
||||
p.f /* ERROR p\.f undefined */ = 0
|
||||
}
|
||||
|
||||
var _ = f0[Sf]
|
||||
@@ -25,8 +29,8 @@ var _ = f0[Sm /* ERROR does not implement */ ]
|
||||
var _ = f0t[Sm /* ERROR does not implement */ ]
|
||||
|
||||
func f1[P interface{ Sf; m() }](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
_ = p.f // ERROR p\.f undefined
|
||||
p.f /* ERROR p\.f undefined */ = 0
|
||||
p.m()
|
||||
}
|
||||
|
||||
@@ -44,8 +48,8 @@ type Sfm struct {
|
||||
func (Sfm) m() {}
|
||||
|
||||
func f2[P interface{ Sfm; m() }](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
_ = p.f // ERROR p\.f undefined
|
||||
p.f /* ERROR p\.f undefined */ = 0
|
||||
p.m()
|
||||
}
|
||||
|
||||
@@ -56,8 +60,8 @@ var _ = f2[Sfm]
|
||||
type PSfm *Sfm
|
||||
|
||||
func f3[P interface{ PSfm }](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
_ = p.f // ERROR p\.f undefined
|
||||
p.f /* ERROR p\.f undefined */ = 0
|
||||
p.m /* ERROR type P has no field or method m */ ()
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Field accesses through type parameters are disabled
|
||||
// until we have a more thorough understanding of the
|
||||
// implications on the spec. See issue #51576.
|
||||
|
||||
package p
|
||||
|
||||
// The first example from the issue.
|
||||
@@ -18,9 +22,12 @@ type numericAbs[T Numeric] interface {
|
||||
// AbsDifference computes the absolute value of the difference of
|
||||
// a and b, where the absolute value is determined by the Abs method.
|
||||
func absDifference[T numericAbs[T /* ERROR T does not implement Numeric */]](a, b T) T {
|
||||
// TODO: the error below should probably be positioned on the '-'.
|
||||
d := a /* ERROR "invalid operation: operator - not defined" */ .Value - b.Value
|
||||
return d.Abs()
|
||||
// Field accesses are not permitted for now. Keep an error so
|
||||
// we can find and fix this code once the situation changes.
|
||||
return a.Value // ERROR a\.Value undefined
|
||||
// TODO: The error below should probably be positioned on the '-'.
|
||||
// d := a /* ERROR "invalid operation: operator - not defined" */ .Value - b.Value
|
||||
// return d.Abs()
|
||||
}
|
||||
|
||||
// The second example from the issue.
|
||||
|
||||
@@ -16,7 +16,7 @@ func G[A, B any](F[A, B]) {
|
||||
|
||||
func _() {
|
||||
// TODO(gri) only report one error below (issue #50932)
|
||||
var x F /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type parameters */ [int]
|
||||
var x F /* ERROR got 1 arguments but 2 type parameters */ [int]
|
||||
G(x /* ERROR does not match */)
|
||||
}
|
||||
|
||||
@@ -46,9 +46,9 @@ func NSG[G any](c RSC[G]) {
|
||||
fmt.Println(c)
|
||||
}
|
||||
|
||||
func MMD[Rc RC /* ERROR cannot infer RG */ /* ERROR got 1 arguments */ [RG], RG any, G any]() M /* ERROR got 2 arguments */ /* ERROR Rc does not match */ [Rc, RG] {
|
||||
func MMD[Rc RC /* ERROR got 1 arguments */ [RG], RG any, G any]() M /* ERROR got 2 arguments */ [Rc, RG] {
|
||||
|
||||
var nFn NFn /* ERROR got 2 arguments */ /* ERROR Rc does not match */ [Rc, RG]
|
||||
var nFn NFn /* ERROR got 2 arguments */ [Rc, RG]
|
||||
|
||||
var empty Rc
|
||||
switch any(empty).(type) {
|
||||
|
||||
164
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51229.go2
vendored
Normal file
164
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51229.go2
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
// Copyright 2022 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
|
||||
|
||||
// Constraint type inference should be independent of the
|
||||
// ordering of the type parameter declarations. Try all
|
||||
// permutations in the test case below.
|
||||
// Permutations produced by https://go.dev/play/p/PHcZNGJTEBZ.
|
||||
|
||||
func f00[S1 ~[]E1, S2 ~[]E2, E1 ~byte, E2 ~byte](S1, S2) {}
|
||||
func f01[S2 ~[]E2, S1 ~[]E1, E1 ~byte, E2 ~byte](S1, S2) {}
|
||||
func f02[E1 ~byte, S1 ~[]E1, S2 ~[]E2, E2 ~byte](S1, S2) {}
|
||||
func f03[S1 ~[]E1, E1 ~byte, S2 ~[]E2, E2 ~byte](S1, S2) {}
|
||||
func f04[S2 ~[]E2, E1 ~byte, S1 ~[]E1, E2 ~byte](S1, S2) {}
|
||||
func f05[E1 ~byte, S2 ~[]E2, S1 ~[]E1, E2 ~byte](S1, S2) {}
|
||||
func f06[E2 ~byte, S2 ~[]E2, S1 ~[]E1, E1 ~byte](S1, S2) {}
|
||||
func f07[S2 ~[]E2, E2 ~byte, S1 ~[]E1, E1 ~byte](S1, S2) {}
|
||||
func f08[S1 ~[]E1, E2 ~byte, S2 ~[]E2, E1 ~byte](S1, S2) {}
|
||||
func f09[E2 ~byte, S1 ~[]E1, S2 ~[]E2, E1 ~byte](S1, S2) {}
|
||||
func f10[S2 ~[]E2, S1 ~[]E1, E2 ~byte, E1 ~byte](S1, S2) {}
|
||||
func f11[S1 ~[]E1, S2 ~[]E2, E2 ~byte, E1 ~byte](S1, S2) {}
|
||||
func f12[S1 ~[]E1, E1 ~byte, E2 ~byte, S2 ~[]E2](S1, S2) {}
|
||||
func f13[E1 ~byte, S1 ~[]E1, E2 ~byte, S2 ~[]E2](S1, S2) {}
|
||||
func f14[E2 ~byte, S1 ~[]E1, E1 ~byte, S2 ~[]E2](S1, S2) {}
|
||||
func f15[S1 ~[]E1, E2 ~byte, E1 ~byte, S2 ~[]E2](S1, S2) {}
|
||||
func f16[E1 ~byte, E2 ~byte, S1 ~[]E1, S2 ~[]E2](S1, S2) {}
|
||||
func f17[E2 ~byte, E1 ~byte, S1 ~[]E1, S2 ~[]E2](S1, S2) {}
|
||||
func f18[E2 ~byte, E1 ~byte, S2 ~[]E2, S1 ~[]E1](S1, S2) {}
|
||||
func f19[E1 ~byte, E2 ~byte, S2 ~[]E2, S1 ~[]E1](S1, S2) {}
|
||||
func f20[S2 ~[]E2, E2 ~byte, E1 ~byte, S1 ~[]E1](S1, S2) {}
|
||||
func f21[E2 ~byte, S2 ~[]E2, E1 ~byte, S1 ~[]E1](S1, S2) {}
|
||||
func f22[E1 ~byte, S2 ~[]E2, E2 ~byte, S1 ~[]E1](S1, S2) {}
|
||||
func f23[S2 ~[]E2, E1 ~byte, E2 ~byte, S1 ~[]E1](S1, S2) {}
|
||||
|
||||
type myByte byte
|
||||
|
||||
func _(a []byte, b []myByte) {
|
||||
f00(a, b)
|
||||
f01(a, b)
|
||||
f02(a, b)
|
||||
f03(a, b)
|
||||
f04(a, b)
|
||||
f05(a, b)
|
||||
f06(a, b)
|
||||
f07(a, b)
|
||||
f08(a, b)
|
||||
f09(a, b)
|
||||
f10(a, b)
|
||||
f11(a, b)
|
||||
f12(a, b)
|
||||
f13(a, b)
|
||||
f14(a, b)
|
||||
f15(a, b)
|
||||
f16(a, b)
|
||||
f17(a, b)
|
||||
f18(a, b)
|
||||
f19(a, b)
|
||||
f20(a, b)
|
||||
f21(a, b)
|
||||
f22(a, b)
|
||||
f23(a, b)
|
||||
}
|
||||
|
||||
// Constraint type inference may have to iterate.
|
||||
// Again, the order of the type parameters shouldn't matter.
|
||||
|
||||
func g0[S ~[]E, M ~map[string]S, E any](m M) {}
|
||||
func g1[M ~map[string]S, S ~[]E, E any](m M) {}
|
||||
func g2[E any, S ~[]E, M ~map[string]S](m M) {}
|
||||
func g3[S ~[]E, E any, M ~map[string]S](m M) {}
|
||||
func g4[M ~map[string]S, E any, S ~[]E](m M) {}
|
||||
func g5[E any, M ~map[string]S, S ~[]E](m M) {}
|
||||
|
||||
func _(m map[string][]byte) {
|
||||
g0(m)
|
||||
g1(m)
|
||||
g2(m)
|
||||
g3(m)
|
||||
g4(m)
|
||||
g5(m)
|
||||
}
|
||||
|
||||
// Worst-case scenario.
|
||||
// There are 10 unknown type parameters. In each iteration of
|
||||
// constraint type inference we infer one more, from right to left.
|
||||
// Each iteration looks repeatedly at all 11 type parameters,
|
||||
// requiring a total of 10*11 = 110 iterations with the current
|
||||
// implementation. Pathological case.
|
||||
|
||||
func h[K any, J ~*K, I ~*J, H ~*I, G ~*H, F ~*G, E ~*F, D ~*E, C ~*D, B ~*C, A ~*B](x A) {}
|
||||
|
||||
func _(x **********int) {
|
||||
h(x)
|
||||
}
|
||||
|
||||
// Examples with channel constraints and tilde.
|
||||
|
||||
func ch1[P chan<- int]() (_ P) { return } // core(P) == chan<- int (single type, no tilde)
|
||||
func ch2[P ~chan int]() { return } // core(P) == ~chan<- int (tilde)
|
||||
func ch3[P chan E, E any](E) { return } // core(P) == chan<- E (single type, no tilde)
|
||||
func ch4[P chan E | ~chan<- E, E any](E) { return } // core(P) == ~chan<- E (tilde)
|
||||
func ch5[P chan int | chan<- int]() { return } // core(P) == chan<- int (not a single type)
|
||||
|
||||
func _() {
|
||||
// P can be inferred as there's a single specific type and no tilde.
|
||||
var _ chan int = ch1 /* ERROR cannot use ch1.*value of type chan<- int */ ()
|
||||
var _ chan<- int = ch1()
|
||||
|
||||
// P cannot be inferred as there's a tilde.
|
||||
ch2( /* ERROR cannot infer P */ )
|
||||
type myChan chan int
|
||||
ch2[myChan]()
|
||||
|
||||
// P can be inferred as there's a single specific type and no tilde.
|
||||
var e int
|
||||
ch3(e)
|
||||
|
||||
// P cannot be inferred as there's more than one specific type and a tilde.
|
||||
ch4( /* ERROR cannot infer P */ e)
|
||||
_ = ch4[chan int]
|
||||
|
||||
// P cannot be inferred as there's more than one specific type.
|
||||
ch5( /* ERROR cannot infer P */ )
|
||||
ch5[chan<- int]()
|
||||
}
|
||||
|
||||
// test case from issue
|
||||
|
||||
func equal[M1 ~map[K1]V1, M2 ~map[K2]V2, K1, K2 ~uint32, V1, V2 ~string](m1 M1, m2 M2) bool {
|
||||
if len(m1) != len(m2) {
|
||||
return false
|
||||
}
|
||||
for k, v1 := range m1 {
|
||||
if v2, ok := m2[K2(k)]; !ok || V2(v1) != v2 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func equalFixed[K1, K2 ~uint32, V1, V2 ~string](m1 map[K1]V1, m2 map[K2]V2) bool {
|
||||
if len(m1) != len(m2) {
|
||||
return false
|
||||
}
|
||||
for k, v1 := range m1 {
|
||||
if v2, ok := m2[K2(k)]; !ok || v1 != V1(v2) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type (
|
||||
someNumericID uint32
|
||||
someStringID string
|
||||
)
|
||||
|
||||
func _() {
|
||||
foo := map[uint32]string{10: "bar"}
|
||||
bar := map[someNumericID]someStringID{10: "bar"}
|
||||
equal(foo, bar)
|
||||
}
|
||||
@@ -11,19 +11,20 @@ type RC[RG any] interface {
|
||||
type Fn[RCT RC[RG], RG any] func(RCT)
|
||||
|
||||
type F[RCT RC[RG], RG any] interface {
|
||||
Fn() Fn[RCT]
|
||||
Fn() Fn /* ERROR got 1 arguments */ [RCT]
|
||||
}
|
||||
|
||||
type concreteF[RCT RC[RG], RG any] struct {
|
||||
makeFn func() Fn[RCT]
|
||||
makeFn func() Fn /* ERROR got 1 arguments */ [RCT]
|
||||
}
|
||||
|
||||
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
|
||||
func (c *concreteF[RCT, RG]) Fn() Fn /* ERROR got 1 arguments */ [RCT] {
|
||||
return c.makeFn()
|
||||
}
|
||||
|
||||
func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] {
|
||||
return &concreteF[RCT]{
|
||||
func NewConcrete[RCT RC[RG], RG any](Rc RCT) F /* ERROR got 1 arguments */ [RCT] {
|
||||
// TODO(rfindley): eliminate the duplicate error below.
|
||||
return & /* ERROR cannot use .* as F\[RCT\] */ concreteF /* ERROR got 1 arguments */ [RCT]{
|
||||
makeFn: nil,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,22 +4,24 @@
|
||||
|
||||
package p
|
||||
|
||||
// As of issue #51527, type-type inference has been disabled.
|
||||
|
||||
type RC[RG any] interface {
|
||||
~[]RG
|
||||
}
|
||||
|
||||
type Fn[RCT RC[RG], RG any] func(RCT)
|
||||
|
||||
type FFn[RCT RC[RG], RG any] func() Fn[RCT]
|
||||
type FFn[RCT RC[RG], RG any] func() Fn /* ERROR got 1 arguments */ [RCT]
|
||||
|
||||
type F[RCT RC[RG], RG any] interface {
|
||||
Fn() Fn[RCT]
|
||||
Fn() Fn /* ERROR got 1 arguments */ [RCT]
|
||||
}
|
||||
|
||||
type concreteF[RCT RC[RG], RG any] struct {
|
||||
makeFn FFn[RCT]
|
||||
makeFn FFn /* ERROR got 1 arguments */ [RCT]
|
||||
}
|
||||
|
||||
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
|
||||
func (c *concreteF[RCT, RG]) Fn() Fn /* ERROR got 1 arguments */ [RCT] {
|
||||
return c.makeFn()
|
||||
}
|
||||
|
||||
@@ -10,7 +10,9 @@ package p
|
||||
type T[P any, B *P] struct{}
|
||||
|
||||
func (T /* ERROR cannot use generic type */ ) m0() {}
|
||||
func (T /* ERROR got 1 type parameter, but receiver base type declares 2 */ [_]) m1() {}
|
||||
|
||||
// TODO(rfindley): eliminate the duplicate errors here.
|
||||
func (T /* ERROR got 1 type parameter, but receiver base type declares 2 */ /* ERROR got 1 arguments but 2 type parameters */ [_]) m1() {}
|
||||
func (T[_, _]) m2() {}
|
||||
// TODO(gri) this error is unfortunate (issue #51343)
|
||||
func (T /* ERROR got 3 arguments but 2 type parameters */ [_, _, _]) m3() {}
|
||||
|
||||
24
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51376.go2
vendored
Normal file
24
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51376.go2
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2022 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
|
||||
|
||||
type Map map[string]int
|
||||
|
||||
func f[M ~map[K]V, K comparable, V any](M) {}
|
||||
func g[M map[K]V, K comparable, V any](M) {}
|
||||
|
||||
func _[M1 ~map[K]V, M2 map[K]V, K comparable, V any]() {
|
||||
var m1 M1
|
||||
f(m1)
|
||||
g( /* ERROR M1 does not implement map\[K\]V */ m1) // M1 has tilde
|
||||
|
||||
var m2 M2
|
||||
f(m2)
|
||||
g(m2) // M1 does not have tilde
|
||||
|
||||
var m3 Map
|
||||
f(m3)
|
||||
g( /* ERROR Map does not implement map\[string\]int */ m3) // M in g does not have tilde
|
||||
}
|
||||
17
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51437.go
vendored
Normal file
17
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51437.go
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2022 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
|
||||
|
||||
type T struct{}
|
||||
|
||||
func (T) m() []int { return nil }
|
||||
|
||||
func f(x T) {
|
||||
for _, x := range func() []int {
|
||||
return x.m() // x declared in parameter list of f
|
||||
}() {
|
||||
_ = x // x declared by range clause
|
||||
}
|
||||
}
|
||||
54
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51472.go2
vendored
Normal file
54
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51472.go2
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright 2022 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 _[T comparable](x T) {
|
||||
_ = x == x
|
||||
}
|
||||
|
||||
func _[T interface{interface{comparable}}](x T) {
|
||||
_ = x == x
|
||||
}
|
||||
|
||||
func _[T interface{comparable; interface{comparable}}](x T) {
|
||||
_ = x == x
|
||||
}
|
||||
|
||||
func _[T interface{comparable; ~int}](x T) {
|
||||
_ = x == x
|
||||
}
|
||||
|
||||
func _[T interface{comparable; ~[]byte}](x T) {
|
||||
_ = x /* ERROR cannot compare */ == x
|
||||
}
|
||||
|
||||
// TODO(gri) The error message here should be better. See issue #51525.
|
||||
func _[T interface{comparable; ~int; ~string}](x T) {
|
||||
_ = x /* ERROR cannot compare */ == x
|
||||
}
|
||||
|
||||
// TODO(gri) The error message here should be better. See issue #51525.
|
||||
func _[T interface{~int; ~string}](x T) {
|
||||
_ = x /* ERROR cannot compare */ == x
|
||||
}
|
||||
|
||||
func _[T interface{comparable; interface{~int}; interface{int|float64}}](x T) {
|
||||
_ = x == x
|
||||
}
|
||||
|
||||
func _[T interface{interface{comparable; ~int}; interface{~float64; comparable; m()}}](x T) {
|
||||
_ = x /* ERROR cannot compare */ == x
|
||||
}
|
||||
|
||||
// test case from issue
|
||||
|
||||
func f[T interface{comparable; []byte|string}](x T) {
|
||||
_ = x == x
|
||||
}
|
||||
|
||||
func _(s []byte) {
|
||||
f( /* ERROR \[\]byte does not implement interface{comparable; \[\]byte\|string} */ s)
|
||||
_ = f[[ /* ERROR does not implement */ ]byte]
|
||||
}
|
||||
7
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51509.go
vendored
Normal file
7
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51509.go
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
// Copyright 2022 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
|
||||
|
||||
type T /* ERROR illegal cycle */ T.x
|
||||
17
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51578.go2
vendored
Normal file
17
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51578.go2
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2022 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
|
||||
|
||||
var _ = (*interface /* ERROR interface contains type constraints */ {int})(nil)
|
||||
|
||||
// abbreviated test case from issue
|
||||
|
||||
type TypeSet interface{ int | string }
|
||||
|
||||
func _() {
|
||||
f((*TypeSet /* ERROR interface contains type constraints */)(nil))
|
||||
}
|
||||
|
||||
func f(any) {}
|
||||
13
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51593.go2
vendored
Normal file
13
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51593.go2
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright 2022 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[P interface{ m(R) }, R any]() {}
|
||||
|
||||
type T = interface { m(int) }
|
||||
|
||||
func _() {
|
||||
_ = f[ /* ERROR cannot infer R */ T] // don't crash in type inference
|
||||
}
|
||||
@@ -31,7 +31,8 @@ func (t *TypeParam) Obj() *TypeName { return t.obj }
|
||||
// or Signature type by calling SetTypeParams. Setting a type parameter on more
|
||||
// than one type will result in a panic.
|
||||
//
|
||||
// The constraint argument can be nil, and set later via SetConstraint.
|
||||
// The constraint argument can be nil, and set later via SetConstraint. If the
|
||||
// constraint is non-nil, it must be fully defined.
|
||||
func NewTypeParam(obj *TypeName, constraint Type) *TypeParam {
|
||||
return (*Checker)(nil).newTypeParam(obj, constraint)
|
||||
}
|
||||
@@ -71,8 +72,10 @@ func (t *TypeParam) Constraint() Type {
|
||||
|
||||
// SetConstraint sets the type constraint for t.
|
||||
//
|
||||
// SetConstraint should not be called concurrently, but once SetConstraint
|
||||
// returns the receiver t is safe for concurrent use.
|
||||
// It must be called by users of NewTypeParam after the bound's underlying is
|
||||
// fully defined, and before using the type parameter in any way other than to
|
||||
// form other types. Once SetConstraint returns the receiver, t is safe for
|
||||
// concurrent use.
|
||||
func (t *TypeParam) SetConstraint(bound Type) {
|
||||
if bound == nil {
|
||||
panic("nil constraint")
|
||||
|
||||
@@ -15,20 +15,25 @@ import (
|
||||
// API
|
||||
|
||||
// A _TypeSet represents the type set of an interface.
|
||||
// Because of existing language restrictions, methods can be "factored out"
|
||||
// from the terms. The actual type set is the intersection of the type set
|
||||
// implied by the methods and the type set described by the terms and the
|
||||
// comparable bit. To test whether a type is included in a type set
|
||||
// ("implements" relation), the type must implement all methods _and_ be
|
||||
// an element of the type set described by the terms and the comparable bit.
|
||||
// If the term list describes the set of all types and comparable is true,
|
||||
// only comparable types are meant; in all other cases comparable is false.
|
||||
type _TypeSet struct {
|
||||
comparable bool // if set, the interface is or embeds comparable
|
||||
// TODO(gri) consider using a set for the methods for faster lookup
|
||||
methods []*Func // all methods of the interface; sorted by unique ID
|
||||
terms termlist // type terms of the type set
|
||||
methods []*Func // all methods of the interface; sorted by unique ID
|
||||
terms termlist // type terms of the type set
|
||||
comparable bool // invariant: !comparable || terms.isAll()
|
||||
}
|
||||
|
||||
// IsEmpty reports whether type set s is the empty set.
|
||||
func (s *_TypeSet) IsEmpty() bool { return s.terms.isEmpty() }
|
||||
|
||||
// IsAll reports whether type set s is the set of all types (corresponding to the empty interface).
|
||||
func (s *_TypeSet) IsAll() bool {
|
||||
return !s.comparable && len(s.methods) == 0 && s.terms.isAll()
|
||||
}
|
||||
func (s *_TypeSet) IsAll() bool { return s.IsMethodSet() && len(s.methods) == 0 }
|
||||
|
||||
// IsMethodSet reports whether the interface t is fully described by its method set.
|
||||
func (s *_TypeSet) IsMethodSet() bool { return !s.comparable && s.terms.isAll() }
|
||||
@@ -43,13 +48,6 @@ func (s *_TypeSet) IsComparable(seen map[Type]bool) bool {
|
||||
})
|
||||
}
|
||||
|
||||
// TODO(gri) IsTypeSet is not a great name for this predicate. Find a better one.
|
||||
|
||||
// IsTypeSet reports whether the type set s is represented by a finite set of underlying types.
|
||||
func (s *_TypeSet) IsTypeSet() bool {
|
||||
return !s.comparable && len(s.methods) == 0
|
||||
}
|
||||
|
||||
// NumMethods returns the number of methods available.
|
||||
func (s *_TypeSet) NumMethods() int { return len(s.methods) }
|
||||
|
||||
@@ -215,12 +213,12 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
|
||||
|
||||
var todo []*Func
|
||||
var seen objset
|
||||
var methods []*Func
|
||||
var allMethods []*Func
|
||||
mpos := make(map[*Func]syntax.Pos) // method specification or method embedding position, for good error messages
|
||||
addMethod := func(pos syntax.Pos, m *Func, explicit bool) {
|
||||
switch other := seen.insert(m); {
|
||||
case other == nil:
|
||||
methods = append(methods, m)
|
||||
allMethods = append(allMethods, m)
|
||||
mpos[m] = pos
|
||||
case explicit:
|
||||
if check == nil {
|
||||
@@ -259,7 +257,8 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
|
||||
}
|
||||
|
||||
// collect embedded elements
|
||||
var allTerms = allTermlist
|
||||
allTerms := allTermlist
|
||||
allComparable := false
|
||||
for i, typ := range ityp.embeddeds {
|
||||
// The embedding position is nil for imported interfaces
|
||||
// and also for interface copies after substitution (but
|
||||
@@ -268,6 +267,7 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
|
||||
if ityp.embedPos != nil {
|
||||
pos = (*ityp.embedPos)[i]
|
||||
}
|
||||
var comparable bool
|
||||
var terms termlist
|
||||
switch u := under(typ).(type) {
|
||||
case *Interface:
|
||||
@@ -279,9 +279,7 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
|
||||
check.versionErrorf(pos, "go1.18", "embedding constraint interface %s", typ)
|
||||
continue
|
||||
}
|
||||
if tset.comparable {
|
||||
ityp.tset.comparable = true
|
||||
}
|
||||
comparable = tset.comparable
|
||||
for _, m := range tset.methods {
|
||||
addMethod(pos, m, false) // use embedding position pos rather than m.pos
|
||||
}
|
||||
@@ -295,6 +293,8 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
|
||||
if tset == &invalidTypeSet {
|
||||
continue // ignore invalid unions
|
||||
}
|
||||
assert(!tset.comparable)
|
||||
assert(len(tset.methods) == 0)
|
||||
terms = tset.terms
|
||||
default:
|
||||
if u == Typ[Invalid] {
|
||||
@@ -306,11 +306,11 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
|
||||
}
|
||||
terms = termlist{{false, typ}}
|
||||
}
|
||||
// The type set of an interface is the intersection
|
||||
// of the type sets of all its elements.
|
||||
// Intersection cannot produce longer termlists and
|
||||
// thus cannot overflow.
|
||||
allTerms = allTerms.intersect(terms)
|
||||
|
||||
// The type set of an interface is the intersection of the type sets of all its elements.
|
||||
// Due to language restrictions, only embedded interfaces can add methods, they are handled
|
||||
// separately. Here we only need to intersect the term lists and comparable bits.
|
||||
allTerms, allComparable = intersectTermLists(allTerms, allComparable, terms, comparable)
|
||||
}
|
||||
ityp.embedPos = nil // not needed anymore (errors have been reported)
|
||||
|
||||
@@ -323,15 +323,46 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
|
||||
}
|
||||
}
|
||||
|
||||
if methods != nil {
|
||||
sortMethods(methods)
|
||||
ityp.tset.methods = methods
|
||||
ityp.tset.comparable = allComparable
|
||||
if len(allMethods) != 0 {
|
||||
sortMethods(allMethods)
|
||||
ityp.tset.methods = allMethods
|
||||
}
|
||||
ityp.tset.terms = allTerms
|
||||
|
||||
return ityp.tset
|
||||
}
|
||||
|
||||
// TODO(gri) The intersectTermLists function belongs to the termlist implementation.
|
||||
// The comparable type set may also be best represented as a term (using
|
||||
// a special type).
|
||||
|
||||
// intersectTermLists computes the intersection of two term lists and respective comparable bits.
|
||||
// xcomp, ycomp are valid only if xterms.isAll() and yterms.isAll() respectively.
|
||||
func intersectTermLists(xterms termlist, xcomp bool, yterms termlist, ycomp bool) (termlist, bool) {
|
||||
terms := xterms.intersect(yterms)
|
||||
// If one of xterms or yterms is marked as comparable,
|
||||
// the result must only include comparable types.
|
||||
comp := xcomp || ycomp
|
||||
if comp && !terms.isAll() {
|
||||
// only keep comparable terms
|
||||
i := 0
|
||||
for _, t := range terms {
|
||||
assert(t.typ != nil)
|
||||
if Comparable(t.typ) {
|
||||
terms[i] = t
|
||||
i++
|
||||
}
|
||||
}
|
||||
terms = terms[:i]
|
||||
if !terms.isAll() {
|
||||
comp = false
|
||||
}
|
||||
}
|
||||
assert(!comp || terms.isAll()) // comparable invariant
|
||||
return terms, comp
|
||||
}
|
||||
|
||||
func sortMethods(list []*Func) {
|
||||
sort.Sort(byUniqueMethodName(list))
|
||||
}
|
||||
|
||||
@@ -25,9 +25,9 @@ func TestTypeSetString(t *testing.T) {
|
||||
"{int; string}": "∅",
|
||||
|
||||
"{comparable}": "{comparable}",
|
||||
"{comparable; int}": "{comparable; int}",
|
||||
"{~int; comparable}": "{comparable; ~int}",
|
||||
"{int|string; comparable}": "{comparable; int ∪ string}",
|
||||
"{comparable; int}": "{int}",
|
||||
"{~int; comparable}": "{~int}",
|
||||
"{int|string; comparable}": "{int ∪ string}",
|
||||
"{comparable; int; string}": "∅",
|
||||
|
||||
"{m()}": "{func (p.T).m()}",
|
||||
@@ -37,8 +37,8 @@ func TestTypeSetString(t *testing.T) {
|
||||
"{m1(); comparable; m2() int }": "{comparable; func (p.T).m1(); func (p.T).m2() int}",
|
||||
"{comparable; error}": "{comparable; func (error).Error() string}",
|
||||
|
||||
"{m(); comparable; int|float32|string}": "{comparable; func (p.T).m(); int ∪ float32 ∪ string}",
|
||||
"{m1(); int; m2(); comparable }": "{comparable; func (p.T).m1(); func (p.T).m2(); int}",
|
||||
"{m(); comparable; int|float32|string}": "{func (p.T).m(); int ∪ float32 ∪ string}",
|
||||
"{m1(); int; m2(); comparable }": "{func (p.T).m1(); func (p.T).m2(); int}",
|
||||
|
||||
"{E}; type E interface{}": "𝓤",
|
||||
"{E}; type E interface{int;string}": "∅",
|
||||
|
||||
@@ -147,10 +147,16 @@ func (check *Checker) typ(e syntax.Expr) Type {
|
||||
// constraint interface.
|
||||
func (check *Checker) varType(e syntax.Expr) Type {
|
||||
typ := check.definedType(e, nil)
|
||||
check.validVarType(e, typ)
|
||||
return typ
|
||||
}
|
||||
|
||||
// validVarType reports an error if typ is a constraint interface.
|
||||
// The expression e is used for error reporting, if any.
|
||||
func (check *Checker) validVarType(e syntax.Expr, typ Type) {
|
||||
// If we have a type parameter there's nothing to do.
|
||||
if isTypeParam(typ) {
|
||||
return typ
|
||||
return
|
||||
}
|
||||
|
||||
// We don't want to call under() or complete interfaces while we are in
|
||||
@@ -169,8 +175,6 @@ func (check *Checker) varType(e syntax.Expr) Type {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return typ
|
||||
}
|
||||
|
||||
// definedType is like typ but also accepts a type name def.
|
||||
@@ -256,7 +260,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
|
||||
|
||||
case *syntax.SelectorExpr:
|
||||
var x operand
|
||||
check.selector(&x, e)
|
||||
check.selector(&x, e, def)
|
||||
|
||||
switch x.mode {
|
||||
case typexpr:
|
||||
@@ -430,10 +434,14 @@ func (check *Checker) instantiatedType(x syntax.Expr, xlist []syntax.Expr, def *
|
||||
// evaluate arguments
|
||||
targs := check.typeList(xlist)
|
||||
if targs == nil {
|
||||
def.setUnderlying(Typ[Invalid]) // avoid later errors due to lazy instantiation
|
||||
def.setUnderlying(Typ[Invalid]) // avoid errors later due to lazy instantiation
|
||||
return Typ[Invalid]
|
||||
}
|
||||
|
||||
// enableTypeTypeInference controls whether to infer missing type arguments
|
||||
// using constraint type inference. See issue #51527.
|
||||
const enableTypeTypeInference = false
|
||||
|
||||
// create the instance
|
||||
ctxt := check.bestContext(nil)
|
||||
h := ctxt.instanceHash(orig, targs)
|
||||
@@ -453,19 +461,18 @@ func (check *Checker) instantiatedType(x syntax.Expr, xlist []syntax.Expr, def *
|
||||
def.setUnderlying(inst)
|
||||
|
||||
inst.resolver = func(ctxt *Context, n *Named) (*TypeParamList, Type, *methodList) {
|
||||
tparams := orig.TypeParams().list()
|
||||
tparams := n.orig.TypeParams().list()
|
||||
|
||||
inferred := targs
|
||||
if len(targs) < len(tparams) {
|
||||
targs := n.targs.list()
|
||||
if enableTypeTypeInference && len(targs) < len(tparams) {
|
||||
// If inference fails, len(inferred) will be 0, and inst.underlying will
|
||||
// be set to Typ[Invalid] in expandNamed.
|
||||
inferred = check.infer(x.Pos(), tparams, targs, nil, nil)
|
||||
inferred := check.infer(x.Pos(), tparams, targs, nil, nil)
|
||||
if len(inferred) > len(targs) {
|
||||
inst.targs = newTypeList(inferred)
|
||||
n.targs = newTypeList(inferred)
|
||||
}
|
||||
}
|
||||
|
||||
check.recordInstance(x, inferred, inst)
|
||||
return expandNamed(ctxt, n, x.Pos())
|
||||
}
|
||||
|
||||
@@ -478,6 +485,7 @@ func (check *Checker) instantiatedType(x syntax.Expr, xlist []syntax.Expr, def *
|
||||
// Since check is non-nil, we can still mutate inst. Unpinning the resolver
|
||||
// frees some memory.
|
||||
inst.resolver = nil
|
||||
check.recordInstance(x, inst.TypeArgs().list(), inst)
|
||||
|
||||
if check.validateTArgLen(x.Pos(), inst.tparams.Len(), inst.targs.Len()) {
|
||||
if i, err := check.verify(x.Pos(), inst.tparams.list(), inst.targs.list()); err != nil {
|
||||
|
||||
@@ -247,6 +247,17 @@ func (d *tparamsList) set(i int, typ Type) {
|
||||
}
|
||||
}
|
||||
|
||||
// unknowns returns the number of type parameters for which no type has been set yet.
|
||||
func (d *tparamsList) unknowns() int {
|
||||
n := 0
|
||||
for _, ti := range d.indices {
|
||||
if ti <= 0 {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// types returns the list of inferred types (via unification) for the type parameters
|
||||
// described by d, and an index. If all types were inferred, the returned index is < 0.
|
||||
// Otherwise, it is the index of the first type parameter which couldn't be inferred;
|
||||
@@ -349,12 +360,16 @@ func (u *unifier) nify(x, y Type, p *ifacePair) (result bool) {
|
||||
if enableCoreTypeUnification && !u.exact {
|
||||
if isTypeParam(x) && !hasName(y) {
|
||||
// When considering the type parameter for unification
|
||||
// we look at the adjusted core type (adjCoreType).
|
||||
// we look at the adjusted core term (adjusted core type
|
||||
// with tilde information).
|
||||
// If the adjusted core type is a named type N; the
|
||||
// corresponding core type is under(N). Since !u.exact
|
||||
// and y doesn't have a name, unification will end up
|
||||
// comparing under(N) to y, so we can just use the core
|
||||
// type instead. Optimization.
|
||||
// type instead. And we can ignore the tilde because we
|
||||
// already look at the underlying types on both sides
|
||||
// and we have known types on both sides.
|
||||
// Optimization.
|
||||
if cx := coreType(x); cx != nil {
|
||||
if traceInference {
|
||||
u.tracef("core %s ≡ %s", x, y)
|
||||
|
||||
@@ -100,25 +100,27 @@ func parseUnion(check *Checker, uexpr syntax.Expr) Type {
|
||||
|
||||
if !Identical(u, t.typ) {
|
||||
check.errorf(tlist[i], "invalid use of ~ (underlying type of %s is %s)", t.typ, u)
|
||||
continue // don't report another error for t
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Stand-alone embedded interfaces are ok and are handled by the single-type case
|
||||
// in the beginning. Embedded interfaces with tilde are excluded above. If we reach
|
||||
// here, we must have at least two terms in the union.
|
||||
if f != nil && !f.typeSet().IsTypeSet() {
|
||||
// here, we must have at least two terms in the syntactic term list (but not necessarily
|
||||
// in the term list of the union's type set).
|
||||
if f != nil {
|
||||
tset := f.typeSet()
|
||||
switch {
|
||||
case f.typeSet().NumMethods() != 0:
|
||||
case tset.NumMethods() != 0:
|
||||
check.errorf(tlist[i], "cannot use %s in union (%s contains methods)", t, t)
|
||||
continue
|
||||
case t.typ == universeComparable.Type():
|
||||
check.error(tlist[i], "cannot use comparable in union")
|
||||
case f.typeSet().comparable:
|
||||
continue
|
||||
case tset.comparable:
|
||||
check.errorf(tlist[i], "cannot use %s in union (%s embeds comparable)", t, t)
|
||||
default:
|
||||
panic("not a type set but no methods and not comparable")
|
||||
continue
|
||||
}
|
||||
continue // don't report another error for t
|
||||
}
|
||||
|
||||
// Report overlapping (non-disjoint) terms such as
|
||||
|
||||
@@ -111,7 +111,7 @@ func defPredeclaredTypes() {
|
||||
typ := NewNamed(obj, nil, nil)
|
||||
|
||||
// interface{} // marked as comparable
|
||||
ityp := &Interface{obj: obj, complete: true, tset: &_TypeSet{true, nil, allTermlist}}
|
||||
ityp := &Interface{obj: obj, complete: true, tset: &_TypeSet{nil, allTermlist, true}}
|
||||
|
||||
typ.SetUnderlying(ityp)
|
||||
def(obj)
|
||||
|
||||
@@ -235,15 +235,7 @@ func methodValueWrapper(dot *ir.SelectorExpr) *ir.Name {
|
||||
saveLineNo := base.Pos
|
||||
ir.CurFunc = nil
|
||||
|
||||
// Set line number equal to the line number where the method is declared.
|
||||
if pos := dot.Selection.Pos; pos.IsKnown() {
|
||||
base.Pos = pos
|
||||
}
|
||||
// Note: !dot.Selection.Pos.IsKnown() happens for method expressions where
|
||||
// the method is implicitly declared. The Error method of the
|
||||
// built-in error type is one such method. We leave the line
|
||||
// number at the use of the method expression in this
|
||||
// case. See issue 29389.
|
||||
base.Pos = base.AutogeneratedPos
|
||||
|
||||
tfn := ir.NewFuncType(base.Pos, nil,
|
||||
typecheck.NewFuncParams(t0.Params(), true),
|
||||
|
||||
@@ -1356,7 +1356,7 @@
|
||||
//
|
||||
// Workspace maintenance
|
||||
//
|
||||
// Go workspace provides access to operations on workspaces.
|
||||
// Work provides access to operations on workspaces.
|
||||
//
|
||||
// Note that support for workspaces is built into many other commands, not
|
||||
// just 'go work'.
|
||||
@@ -1364,6 +1364,12 @@
|
||||
// See 'go help modules' for information about Go's module system of which
|
||||
// workspaces are a part.
|
||||
//
|
||||
// See https://go.dev/ref/mod#workspaces for an in-depth reference on
|
||||
// workspaces.
|
||||
//
|
||||
// See https://go.dev/doc/tutorial/workspaces for an introductory
|
||||
// tutorial on workspaces.
|
||||
//
|
||||
// A workspace is specified by a go.work file that specifies a set of
|
||||
// module directories with the "use" directive. These modules are used as
|
||||
// root modules by the go command for builds and related operations. A
|
||||
@@ -1485,9 +1491,8 @@
|
||||
// Version string
|
||||
// }
|
||||
//
|
||||
// See the workspaces design proposal at
|
||||
// https://go.googlesource.com/proposal/+/master/design/45713-workspace.md for
|
||||
// more information.
|
||||
// See the workspaces reference at https://go.dev/ref/mod#workspaces
|
||||
// for more information.
|
||||
//
|
||||
//
|
||||
// Initialize workspace file
|
||||
@@ -1507,6 +1512,9 @@
|
||||
// Each argument path is added to a use directive in the go.work file. The
|
||||
// current go version will also be listed in the go.work file.
|
||||
//
|
||||
// See the workspaces reference at https://go.dev/ref/mod#workspaces
|
||||
// for more information.
|
||||
//
|
||||
//
|
||||
// Sync workspace build list to modules
|
||||
//
|
||||
@@ -1530,12 +1538,15 @@
|
||||
// build list's version of each module is always the same or higher than
|
||||
// that in each workspace module.
|
||||
//
|
||||
// See the workspaces reference at https://go.dev/ref/mod#workspaces
|
||||
// for more information.
|
||||
//
|
||||
//
|
||||
// Add modules to workspace file
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// go work use [-r] [moddirs]
|
||||
// go work use [-r] moddirs
|
||||
//
|
||||
// Use provides a command-line interface for adding
|
||||
// directories, optionally recursively, to a go.work file.
|
||||
@@ -1549,6 +1560,9 @@
|
||||
// were specified as arguments: namely, use directives will be added for
|
||||
// directories that exist, and removed for directories that do not exist.
|
||||
//
|
||||
// See the workspaces reference at https://go.dev/ref/mod#workspaces
|
||||
// for more information.
|
||||
//
|
||||
//
|
||||
// Compile and run Go program
|
||||
//
|
||||
|
||||
@@ -288,6 +288,11 @@ func BinDir() string {
|
||||
// operate in workspace mode. It should not be called by other commands,
|
||||
// for example 'go mod tidy', that don't operate in workspace mode.
|
||||
func InitWorkfile() {
|
||||
if RootMode == NoRoot {
|
||||
workFilePath = ""
|
||||
return
|
||||
}
|
||||
|
||||
switch gowork := cfg.Getenv("GOWORK"); gowork {
|
||||
case "off":
|
||||
workFilePath = ""
|
||||
|
||||
@@ -802,7 +802,7 @@ var latestVersionIgnoringRetractionsCache par.Cache // path → queryLatestVersi
|
||||
// an absolute path or a relative path starting with a '.' or '..'
|
||||
// path component.
|
||||
func ToDirectoryPath(path string) string {
|
||||
if modfile.IsDirectoryPath(path) {
|
||||
if path == "." || modfile.IsDirectoryPath(path) {
|
||||
return path
|
||||
}
|
||||
// The path is not a relative path or an absolute path, so make it relative
|
||||
|
||||
@@ -73,8 +73,6 @@ func printStderr(args ...any) (int, error) {
|
||||
}
|
||||
|
||||
func runRun(ctx context.Context, cmd *base.Command, args []string) {
|
||||
modload.InitWorkfile()
|
||||
|
||||
if shouldUseOutsideModuleMode(args) {
|
||||
// Set global module flags for 'go run cmd@version'.
|
||||
// This must be done before modload.Init, but we need to call work.BuildInit
|
||||
@@ -84,7 +82,10 @@ func runRun(ctx context.Context, cmd *base.Command, args []string) {
|
||||
modload.RootMode = modload.NoRoot
|
||||
modload.AllowMissingModuleImports()
|
||||
modload.Init()
|
||||
} else {
|
||||
modload.InitWorkfile()
|
||||
}
|
||||
|
||||
work.BuildInit()
|
||||
var b work.Builder
|
||||
b.Init()
|
||||
|
||||
@@ -312,7 +312,7 @@ func gitStatus(vcsGit *Cmd, rootDir string) (Status, error) {
|
||||
// uncommitted files and skip tagging revision / committime.
|
||||
var rev string
|
||||
var commitTime time.Time
|
||||
out, err = vcsGit.runOutputVerboseOnly(rootDir, "show -s --no-show-signature --format=%H:%ct")
|
||||
out, err = vcsGit.runOutputVerboseOnly(rootDir, "-c log.showsignature=false show -s --format=%H:%ct")
|
||||
if err != nil && !uncommitted {
|
||||
return Status{}, err
|
||||
} else if err == nil {
|
||||
|
||||
@@ -84,9 +84,8 @@ writing it back to go.mod. The JSON output corresponds to these Go types:
|
||||
Version string
|
||||
}
|
||||
|
||||
See the workspaces design proposal at
|
||||
https://go.googlesource.com/proposal/+/master/design/45713-workspace.md for
|
||||
more information.
|
||||
See the workspaces reference at https://go.dev/ref/mod#workspaces
|
||||
for more information.
|
||||
`,
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ modules will be created.
|
||||
Each argument path is added to a use directive in the go.work file. The
|
||||
current go version will also be listed in the go.work file.
|
||||
|
||||
See the workspaces reference at https://go.dev/ref/mod#workspaces
|
||||
for more information.
|
||||
`,
|
||||
Run: runInit,
|
||||
}
|
||||
|
||||
@@ -33,6 +33,9 @@ if the dependency module's version is not already the same as the build
|
||||
list's version. Note that Minimal Version Selection guarantees that the
|
||||
build list's version of each module is always the same or higher than
|
||||
that in each workspace module.
|
||||
|
||||
See the workspaces reference at https://go.dev/ref/mod#workspaces
|
||||
for more information.
|
||||
`,
|
||||
Run: runSync,
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
)
|
||||
|
||||
var cmdUse = &base.Command{
|
||||
UsageLine: "go work use [-r] [moddirs]",
|
||||
UsageLine: "go work use [-r] moddirs",
|
||||
Short: "add modules to workspace file",
|
||||
Long: `Use provides a command-line interface for adding
|
||||
directories, optionally recursively, to a go.work file.
|
||||
@@ -33,6 +33,9 @@ The -r flag searches recursively for modules in the argument
|
||||
directories, and the use command operates as if each of the directories
|
||||
were specified as arguments: namely, use directives will be added for
|
||||
directories that exist, and removed for directories that do not exist.
|
||||
|
||||
See the workspaces reference at https://go.dev/ref/mod#workspaces
|
||||
for more information.
|
||||
`,
|
||||
}
|
||||
|
||||
@@ -101,6 +104,9 @@ func runUse(ctx context.Context, cmd *base.Command, args []string) {
|
||||
keepDirs[absDir] = dir
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
base.Fatalf("go: 'go work use' requires one or more directory arguments")
|
||||
}
|
||||
for _, useDir := range args {
|
||||
if !*useR {
|
||||
lookDir(useDir)
|
||||
@@ -186,5 +192,5 @@ func pathRel(workDir, dir string) (abs, canonical string) {
|
||||
|
||||
// Normalize relative paths to use slashes, so that checked-in go.work
|
||||
// files with relative paths within the repo are platform-independent.
|
||||
return abs, filepath.ToSlash(rel)
|
||||
return abs, modload.ToDirectoryPath(rel)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
var CmdWork = &base.Command{
|
||||
UsageLine: "go work",
|
||||
Short: "workspace maintenance",
|
||||
Long: `Go workspace provides access to operations on workspaces.
|
||||
Long: `Work provides access to operations on workspaces.
|
||||
|
||||
Note that support for workspaces is built into many other commands, not
|
||||
just 'go work'.
|
||||
@@ -20,6 +20,12 @@ just 'go work'.
|
||||
See 'go help modules' for information about Go's module system of which
|
||||
workspaces are a part.
|
||||
|
||||
See https://go.dev/ref/mod#workspaces for an in-depth reference on
|
||||
workspaces.
|
||||
|
||||
See https://go.dev/doc/tutorial/workspaces for an introductory
|
||||
tutorial on workspaces.
|
||||
|
||||
A workspace is specified by a go.work file that specifies a set of
|
||||
module directories with the "use" directive. These modules are used as
|
||||
root modules by the go command for builds and related operations. A
|
||||
|
||||
16
src/cmd/go/testdata/script/run_work_versioned.txt
vendored
Normal file
16
src/cmd/go/testdata/script/run_work_versioned.txt
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
[short] skip
|
||||
go run example.com/printversion@v0.1.0
|
||||
stdout '^main is example.com/printversion v0.1.0$'
|
||||
|
||||
-- go.work --
|
||||
go 1.18
|
||||
|
||||
use (
|
||||
.
|
||||
)
|
||||
-- go.mod --
|
||||
module example
|
||||
|
||||
go 1.18
|
||||
|
||||
require example.com/printversion v1.0.0
|
||||
84
src/cmd/go/testdata/script/test_fuzz_minimize_dirty_cov.txt
vendored
Normal file
84
src/cmd/go/testdata/script/test_fuzz_minimize_dirty_cov.txt
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
# Test that minimization doesn't use dirty coverage snapshots when it
|
||||
# is unable to actually minimize the input. We do this by checking that
|
||||
# a expected value appears in the cache. If a dirty coverage map is used
|
||||
# (i.e. the coverage map generated during the last minimization step,
|
||||
# rather than the map provided with the initial input) then this value
|
||||
# is unlikely to appear in the cache, since the map generated during
|
||||
# the last minimization step should not increase the coverage.
|
||||
|
||||
[short] skip
|
||||
[!fuzz-instrumented] skip
|
||||
|
||||
env GOCACHE=$WORK/gocache
|
||||
go test -fuzz=FuzzCovMin -fuzztime=25s -test.fuzzcachedir=$GOCACHE/fuzz
|
||||
go run check_file/main.go $GOCACHE/fuzz/FuzzCovMin abcd
|
||||
|
||||
-- go.mod --
|
||||
module test
|
||||
|
||||
-- covmin_test.go --
|
||||
package covmin
|
||||
|
||||
import "testing"
|
||||
|
||||
func FuzzCovMin(f *testing.F) {
|
||||
f.Fuzz(func(t *testing.T, data []byte) {
|
||||
if len(data) >= 4 && data[0] == 'a' && data[1] == 'b' && data[2] == 'c' && data[3] == 'd' {
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
-- check_file/main.go --
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func checkFile(name, expected string) (bool, error) {
|
||||
data, err := os.ReadFile(name)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, line := range bytes.Split(data, []byte("\n")) {
|
||||
m := valRe.FindSubmatch(line)
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
fmt.Println(strconv.Unquote(string(m[1])))
|
||||
if s, err := strconv.Unquote(string(m[1])); err != nil {
|
||||
return false, err
|
||||
} else if s == expected {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
var valRe = regexp.MustCompile(`^\[\]byte\(([^)]+)\)$`)
|
||||
|
||||
func main() {
|
||||
dir, expected := os.Args[1], os.Args[2]
|
||||
ents, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
for _, ent := range ents {
|
||||
name := filepath.Join(dir, ent.Name())
|
||||
if good, err := checkFile(name, expected); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
} else if good {
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
fmt.Fprintln(os.Stderr, "input over minimized")
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -127,19 +127,8 @@ func FuzzMinCache(f *testing.F) {
|
||||
if bytes.Equal(buf, seed) {
|
||||
return
|
||||
}
|
||||
if n := sum(buf); n < 0 {
|
||||
t.Error("sum cannot be negative")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func sum(buf []byte) int {
|
||||
n := 0
|
||||
for _, b := range buf {
|
||||
n += int(b)
|
||||
}
|
||||
return n
|
||||
}
|
||||
-- check_testdata/check_testdata.go --
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
@@ -111,7 +111,7 @@ rm $GOBIN/d$GOEXE
|
||||
go list -x ./...
|
||||
stdout -count=3 '^example.com'
|
||||
stderr -count=1 '^git status'
|
||||
stderr -count=1 '^git show'
|
||||
stderr -count=1 '^git -c log.showsignature=false show'
|
||||
|
||||
-- $WORK/fakebin/git --
|
||||
#!/bin/sh
|
||||
|
||||
17
src/cmd/go/testdata/script/work_init_path.txt
vendored
Normal file
17
src/cmd/go/testdata/script/work_init_path.txt
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# Regression test for https://go.dev/issue/51448.
|
||||
# 'go work init . foo/bar' should produce a go.work file
|
||||
# with the same paths as 'go work init; go work use -r .'.
|
||||
|
||||
go work init . foo/bar
|
||||
mv go.work go.work.init
|
||||
|
||||
go work init
|
||||
go work use -r .
|
||||
cmp go.work go.work.init
|
||||
|
||||
-- go.mod --
|
||||
module example
|
||||
go 1.18
|
||||
-- foo/bar/go.mod --
|
||||
module example
|
||||
go 1.18
|
||||
10
src/cmd/go/testdata/script/work_use.txt
vendored
10
src/cmd/go/testdata/script/work_use.txt
vendored
@@ -14,16 +14,16 @@ use (
|
||||
go 1.18
|
||||
|
||||
use (
|
||||
foo
|
||||
foo/bar/baz
|
||||
./foo
|
||||
./foo/bar/baz
|
||||
)
|
||||
-- go.want_work_other --
|
||||
go 1.18
|
||||
|
||||
use (
|
||||
foo
|
||||
foo/bar/baz
|
||||
other
|
||||
./foo
|
||||
./foo/bar/baz
|
||||
./other
|
||||
)
|
||||
-- foo/go.mod --
|
||||
module foo
|
||||
|
||||
@@ -6,13 +6,13 @@ go 1.18
|
||||
|
||||
use (
|
||||
.
|
||||
sub
|
||||
sub/dir/deleted
|
||||
./sub
|
||||
./sub/dir/deleted
|
||||
)
|
||||
-- go.work.want --
|
||||
go 1.18
|
||||
|
||||
use sub/dir
|
||||
use ./sub/dir
|
||||
-- sub/README.txt --
|
||||
A go.mod file has been deleted from this directory.
|
||||
In addition, the entire subdirectory sub/dir/deleted
|
||||
|
||||
4
src/cmd/go/testdata/script/work_use_dot.txt
vendored
4
src/cmd/go/testdata/script/work_use_dot.txt
vendored
@@ -31,7 +31,7 @@ grep '^use ["]?'$PWD'["]?$' ../../go.work
|
||||
# resulting workspace would contain a duplicate module.
|
||||
cp ../../go.work.orig ../../go.work
|
||||
! go work use $PWD .
|
||||
stderr '^go: already added "bar/baz" as "'$PWD'"$'
|
||||
stderr '^go: already added "\./bar/baz" as "'$PWD'"$'
|
||||
cmp ../../go.work ../../go.work.orig
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ go 1.18
|
||||
-- go.work.rel --
|
||||
go 1.18
|
||||
|
||||
use bar/baz
|
||||
use ./bar/baz
|
||||
-- bar/baz/go.mod --
|
||||
module example/bar/baz
|
||||
go 1.18
|
||||
|
||||
11
src/cmd/go/testdata/script/work_use_noargs.txt
vendored
Normal file
11
src/cmd/go/testdata/script/work_use_noargs.txt
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
# For now, 'go work use' requires arguments.
|
||||
# (Eventually, we may may it implicitly behave like 'go work use .'.
|
||||
|
||||
! go work use
|
||||
stderr '^go: ''go work use'' requires one or more directory arguments'
|
||||
|
||||
! go work use -r
|
||||
stderr '^go: ''go work use'' requires one or more directory arguments'
|
||||
|
||||
-- go.work --
|
||||
go 1.18
|
||||
@@ -319,9 +319,17 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
|
||||
}
|
||||
}
|
||||
|
||||
func (p *printer) parameters(fields *ast.FieldList, isTypeParam bool) {
|
||||
type paramMode int
|
||||
|
||||
const (
|
||||
funcParam paramMode = iota
|
||||
funcTParam
|
||||
typeTParam
|
||||
)
|
||||
|
||||
func (p *printer) parameters(fields *ast.FieldList, mode paramMode) {
|
||||
openTok, closeTok := token.LPAREN, token.RPAREN
|
||||
if isTypeParam {
|
||||
if mode != funcParam {
|
||||
openTok, closeTok = token.LBRACK, token.RBRACK
|
||||
}
|
||||
p.print(fields.Opening, openTok)
|
||||
@@ -373,7 +381,7 @@ func (p *printer) parameters(fields *ast.FieldList, isTypeParam bool) {
|
||||
if closing := p.lineFor(fields.Closing); 0 < prevLine && prevLine < closing {
|
||||
p.print(token.COMMA)
|
||||
p.linebreak(closing, 0, ignore, true)
|
||||
} else if isTypeParam && fields.NumFields() == 1 {
|
||||
} else if mode == typeTParam && fields.NumFields() == 1 {
|
||||
// Otherwise, if we are in a type parameter list that could be confused
|
||||
// with the constant array length expression [P*C], print a comma so that
|
||||
// parsing is unambiguous.
|
||||
@@ -411,10 +419,10 @@ func isTypeLit(x ast.Expr) bool {
|
||||
|
||||
func (p *printer) signature(sig *ast.FuncType) {
|
||||
if sig.TypeParams != nil {
|
||||
p.parameters(sig.TypeParams, true)
|
||||
p.parameters(sig.TypeParams, funcTParam)
|
||||
}
|
||||
if sig.Params != nil {
|
||||
p.parameters(sig.Params, false)
|
||||
p.parameters(sig.Params, funcParam)
|
||||
} else {
|
||||
p.print(token.LPAREN, token.RPAREN)
|
||||
}
|
||||
@@ -428,7 +436,7 @@ func (p *printer) signature(sig *ast.FuncType) {
|
||||
p.expr(stripParensAlways(res.List[0].Type))
|
||||
return
|
||||
}
|
||||
p.parameters(res, false)
|
||||
p.parameters(res, funcParam)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1639,7 +1647,7 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
|
||||
p.setComment(s.Doc)
|
||||
p.expr(s.Name)
|
||||
if s.TypeParams != nil {
|
||||
p.parameters(s.TypeParams, true)
|
||||
p.parameters(s.TypeParams, typeTParam)
|
||||
}
|
||||
if n == 1 {
|
||||
p.print(blank)
|
||||
@@ -1829,7 +1837,7 @@ func (p *printer) funcDecl(d *ast.FuncDecl) {
|
||||
// FUNC is emitted).
|
||||
startCol := p.out.Column - len("func ")
|
||||
if d.Recv != nil {
|
||||
p.parameters(d.Recv, false) // method: print receiver
|
||||
p.parameters(d.Recv, funcParam) // method: print receiver
|
||||
p.print(blank)
|
||||
}
|
||||
p.expr(d.Name)
|
||||
|
||||
26
src/go/printer/testdata/generics.golden
vendored
26
src/go/printer/testdata/generics.golden
vendored
@@ -64,3 +64,29 @@ type _ [P*T - T]struct{}
|
||||
type _[
|
||||
P *T,
|
||||
] struct{}
|
||||
|
||||
// equivalent test cases for potentially ambiguous type parameter lists, except
|
||||
// for function declarations there is no ambiguity (issue #51548)
|
||||
func _[P *T]() {}
|
||||
func _[P *T, _ any]() {}
|
||||
func _[P *T]() {}
|
||||
func _[P *T, _ any]() {}
|
||||
func _[P T]() {}
|
||||
func _[P T, _ any]() {}
|
||||
|
||||
func _[P *struct{}]() {}
|
||||
func _[P *struct{}]() {}
|
||||
func _[P []int]() {}
|
||||
|
||||
func _[P T]() {}
|
||||
func _[P T]() {}
|
||||
func _[P **T]() {}
|
||||
func _[P *T]() {}
|
||||
func _[P *T]() {}
|
||||
func _[P **T]() {}
|
||||
func _[P *T]() {}
|
||||
|
||||
func _[
|
||||
P *T,
|
||||
]() {
|
||||
}
|
||||
|
||||
25
src/go/printer/testdata/generics.input
vendored
25
src/go/printer/testdata/generics.input
vendored
@@ -61,3 +61,28 @@ type _ [P * T - T]struct{}
|
||||
type _[
|
||||
P *T,
|
||||
] struct{}
|
||||
|
||||
// equivalent test cases for potentially ambiguous type parameter lists, except
|
||||
// for function declarations there is no ambiguity (issue #51548)
|
||||
func _[P *T,]() {}
|
||||
func _[P *T, _ any]() {}
|
||||
func _[P (*T),]() {}
|
||||
func _[P (*T), _ any]() {}
|
||||
func _[P (T),]() {}
|
||||
func _[P (T), _ any]() {}
|
||||
|
||||
func _[P *struct{}] () {}
|
||||
func _[P (*struct{})] () {}
|
||||
func _[P ([]int)] () {}
|
||||
|
||||
func _ [P(T)]() {}
|
||||
func _ [P((T))]() {}
|
||||
func _ [P * *T]() {}
|
||||
func _ [P * T]() {}
|
||||
func _ [P(*T)]() {}
|
||||
func _ [P(**T)]() {}
|
||||
func _ [P * T]() {}
|
||||
|
||||
func _[
|
||||
P *T,
|
||||
]() {}
|
||||
|
||||
@@ -199,12 +199,12 @@ type Info struct {
|
||||
// qualified identifiers are collected in the Uses map.
|
||||
Types map[ast.Expr]TypeAndValue
|
||||
|
||||
// Instances maps identifiers denoting parameterized types or functions to
|
||||
// their type arguments and instantiated type.
|
||||
// Instances maps identifiers denoting generic types or functions to their
|
||||
// type arguments and instantiated type.
|
||||
//
|
||||
// For example, Instances will map the identifier for 'T' in the type
|
||||
// instantiation T[int, string] to the type arguments [int, string] and
|
||||
// resulting instantiated *Named type. Given a parameterized function
|
||||
// resulting instantiated *Named type. Given a generic function
|
||||
// func F[A any](A), Instances will map the identifier for 'F' in the call
|
||||
// expression F(int(1)) to the inferred type arguments [int], and resulting
|
||||
// instantiated *Signature.
|
||||
@@ -417,8 +417,11 @@ func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, i
|
||||
}
|
||||
|
||||
// AssertableTo reports whether a value of type V can be asserted to have type T.
|
||||
// The behavior of AssertableTo is undefined if V is a generalized interface; i.e.,
|
||||
// an interface that may only be used as a type constraint in Go code.
|
||||
//
|
||||
// The behavior of AssertableTo is undefined in two cases:
|
||||
// - if V is a generalized interface; i.e., an interface that may only be used
|
||||
// as a type constraint in Go code
|
||||
// - if T is an uninstantiated generic type
|
||||
func AssertableTo(V *Interface, T Type) bool {
|
||||
// Checker.newAssertableTo suppresses errors for invalid types, so we need special
|
||||
// handling here.
|
||||
@@ -428,20 +431,31 @@ func AssertableTo(V *Interface, T Type) bool {
|
||||
return (*Checker)(nil).newAssertableTo(V, T) == nil
|
||||
}
|
||||
|
||||
// AssignableTo reports whether a value of type V is assignable to a variable of type T.
|
||||
// AssignableTo reports whether a value of type V is assignable to a variable
|
||||
// of type T.
|
||||
//
|
||||
// The behavior of AssignableTo is undefined if V or T is an uninstantiated
|
||||
// generic type.
|
||||
func AssignableTo(V, T Type) bool {
|
||||
x := operand{mode: value, typ: V}
|
||||
ok, _ := x.assignableTo(nil, T, nil) // check not needed for non-constant x
|
||||
return ok
|
||||
}
|
||||
|
||||
// ConvertibleTo reports whether a value of type V is convertible to a value of type T.
|
||||
// ConvertibleTo reports whether a value of type V is convertible to a value of
|
||||
// type T.
|
||||
//
|
||||
// The behavior of ConvertibleTo is undefined if V or T is an uninstantiated
|
||||
// generic type.
|
||||
func ConvertibleTo(V, T Type) bool {
|
||||
x := operand{mode: value, typ: V}
|
||||
return x.convertibleTo(nil, T, nil) // check not needed for non-constant x
|
||||
}
|
||||
|
||||
// Implements reports whether type V implements interface T.
|
||||
//
|
||||
// The behavior of Implements is undefined if V is an uninstantiated generic
|
||||
// type.
|
||||
func Implements(V Type, T *Interface) bool {
|
||||
if T.Empty() {
|
||||
// All types (even Typ[Invalid]) implement the empty interface.
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"internal/testenv"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -434,129 +435,146 @@ func TestTypesInfo(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestInstanceInfo(t *testing.T) {
|
||||
var tests = []struct {
|
||||
src string
|
||||
name string
|
||||
targs []string
|
||||
typ string
|
||||
}{
|
||||
{`package p0; func f[T any](T) {}; func _() { f(42) }`,
|
||||
`f`,
|
||||
[]string{`int`},
|
||||
`func(int)`,
|
||||
},
|
||||
{`package p1; func f[T any](T) T { panic(0) }; func _() { f('@') }`,
|
||||
`f`,
|
||||
[]string{`rune`},
|
||||
`func(rune) rune`,
|
||||
},
|
||||
{`package p2; func f[T any](...T) T { panic(0) }; func _() { f(0i) }`,
|
||||
`f`,
|
||||
[]string{`complex128`},
|
||||
`func(...complex128) complex128`,
|
||||
},
|
||||
{`package p3; func f[A, B, C any](A, *B, []C) {}; func _() { f(1.2, new(string), []byte{}) }`,
|
||||
`f`,
|
||||
[]string{`float64`, `string`, `byte`},
|
||||
`func(float64, *string, []byte)`,
|
||||
},
|
||||
{`package p4; func f[A, B any](A, *B, ...[]B) {}; func _() { f(1.2, new(byte)) }`,
|
||||
`f`,
|
||||
[]string{`float64`, `byte`},
|
||||
`func(float64, *byte, ...[]byte)`,
|
||||
},
|
||||
|
||||
{`package s1; func f[T any, P interface{~*T}](x T) {}; func _(x string) { f(x) }`,
|
||||
`f`,
|
||||
[]string{`string`, `*string`},
|
||||
`func(x string)`,
|
||||
},
|
||||
{`package s2; func f[T any, P interface{~*T}](x []T) {}; func _(x []int) { f(x) }`,
|
||||
`f`,
|
||||
[]string{`int`, `*int`},
|
||||
`func(x []int)`,
|
||||
},
|
||||
{`package s3; type C[T any] interface{~chan<- T}; func f[T any, P C[T]](x []T) {}; func _(x []int) { f(x) }`,
|
||||
`f`,
|
||||
[]string{`int`, `chan<- int`},
|
||||
`func(x []int)`,
|
||||
},
|
||||
{`package s4; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T) {}; func _(x []int) { f(x) }`,
|
||||
`f`,
|
||||
[]string{`int`, `chan<- int`, `chan<- []*chan<- int`},
|
||||
`func(x []int)`,
|
||||
},
|
||||
|
||||
{`package t1; func f[T any, P interface{~*T}]() T { panic(0) }; func _() { _ = f[string] }`,
|
||||
`f`,
|
||||
[]string{`string`, `*string`},
|
||||
`func() string`,
|
||||
},
|
||||
{`package t2; func f[T any, P interface{~*T}]() T { panic(0) }; func _() { _ = (f[string]) }`,
|
||||
`f`,
|
||||
[]string{`string`, `*string`},
|
||||
`func() string`,
|
||||
},
|
||||
{`package t3; type C[T any] interface{~chan<- T}; func f[T any, P C[T]]() []T { return nil }; func _() { _ = f[int] }`,
|
||||
`f`,
|
||||
[]string{`int`, `chan<- int`},
|
||||
`func() []int`,
|
||||
},
|
||||
{`package t4; type C[T any] interface{~chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = f[int] }`,
|
||||
`f`,
|
||||
[]string{`int`, `chan<- int`, `chan<- []*chan<- int`},
|
||||
`func() []int`,
|
||||
},
|
||||
{`package i0; import "lib"; func _() { lib.F(42) }`,
|
||||
`F`,
|
||||
[]string{`int`},
|
||||
`func(int)`,
|
||||
},
|
||||
{`package type0; type T[P interface{~int}] struct{ x P }; var _ T[int]`,
|
||||
`T`,
|
||||
[]string{`int`},
|
||||
`struct{x int}`,
|
||||
},
|
||||
{`package type1; type T[P interface{~int}] struct{ x P }; var _ (T[int])`,
|
||||
`T`,
|
||||
[]string{`int`},
|
||||
`struct{x int}`,
|
||||
},
|
||||
{`package type2; type T[P interface{~int}] struct{ x P }; var _ T[(int)]`,
|
||||
`T`,
|
||||
[]string{`int`},
|
||||
`struct{x int}`,
|
||||
},
|
||||
{`package type3; type T[P1 interface{~[]P2}, P2 any] struct{ x P1; y P2 }; var _ T[[]int, int]`,
|
||||
`T`,
|
||||
[]string{`[]int`, `int`},
|
||||
`struct{x []int; y int}`,
|
||||
},
|
||||
{`package type4; import "lib"; var _ lib.T[int]`,
|
||||
`T`,
|
||||
[]string{`int`},
|
||||
`[]int`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
const lib = `package lib
|
||||
const lib = `package lib
|
||||
|
||||
func F[P any](P) {}
|
||||
|
||||
type T[P any] []P
|
||||
`
|
||||
|
||||
type testInst struct {
|
||||
name string
|
||||
targs []string
|
||||
typ string
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
src string
|
||||
instances []testInst // recorded instances in source order
|
||||
}{
|
||||
{`package p0; func f[T any](T) {}; func _() { f(42) }`,
|
||||
[]testInst{{`f`, []string{`int`}, `func(int)`}},
|
||||
},
|
||||
{`package p1; func f[T any](T) T { panic(0) }; func _() { f('@') }`,
|
||||
[]testInst{{`f`, []string{`rune`}, `func(rune) rune`}},
|
||||
},
|
||||
{`package p2; func f[T any](...T) T { panic(0) }; func _() { f(0i) }`,
|
||||
[]testInst{{`f`, []string{`complex128`}, `func(...complex128) complex128`}},
|
||||
},
|
||||
{`package p3; func f[A, B, C any](A, *B, []C) {}; func _() { f(1.2, new(string), []byte{}) }`,
|
||||
[]testInst{{`f`, []string{`float64`, `string`, `byte`}, `func(float64, *string, []byte)`}},
|
||||
},
|
||||
{`package p4; func f[A, B any](A, *B, ...[]B) {}; func _() { f(1.2, new(byte)) }`,
|
||||
[]testInst{{`f`, []string{`float64`, `byte`}, `func(float64, *byte, ...[]byte)`}},
|
||||
},
|
||||
|
||||
{`package s1; func f[T any, P interface{*T}](x T) {}; func _(x string) { f(x) }`,
|
||||
[]testInst{{`f`, []string{`string`, `*string`}, `func(x string)`}},
|
||||
},
|
||||
{`package s2; func f[T any, P interface{*T}](x []T) {}; func _(x []int) { f(x) }`,
|
||||
[]testInst{{`f`, []string{`int`, `*int`}, `func(x []int)`}},
|
||||
},
|
||||
{`package s3; type C[T any] interface{chan<- T}; func f[T any, P C[T]](x []T) {}; func _(x []int) { f(x) }`,
|
||||
[]testInst{
|
||||
{`C`, []string{`T`}, `interface{chan<- T}`},
|
||||
{`f`, []string{`int`, `chan<- int`}, `func(x []int)`},
|
||||
},
|
||||
},
|
||||
{`package s4; type C[T any] interface{chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T) {}; func _(x []int) { f(x) }`,
|
||||
[]testInst{
|
||||
{`C`, []string{`T`}, `interface{chan<- T}`},
|
||||
{`C`, []string{`[]*P`}, `interface{chan<- []*P}`},
|
||||
{`f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func(x []int)`},
|
||||
},
|
||||
},
|
||||
|
||||
{`package t1; func f[T any, P interface{*T}]() T { panic(0) }; func _() { _ = f[string] }`,
|
||||
[]testInst{{`f`, []string{`string`, `*string`}, `func() string`}},
|
||||
},
|
||||
{`package t2; func f[T any, P interface{*T}]() T { panic(0) }; func _() { _ = (f[string]) }`,
|
||||
[]testInst{{`f`, []string{`string`, `*string`}, `func() string`}},
|
||||
},
|
||||
{`package t3; type C[T any] interface{chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = f[int] }`,
|
||||
[]testInst{
|
||||
{`C`, []string{`T`}, `interface{chan<- T}`},
|
||||
{`C`, []string{`[]*P`}, `interface{chan<- []*P}`},
|
||||
{`f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func() []int`},
|
||||
},
|
||||
},
|
||||
{`package t4; type C[T any] interface{chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = (f[int]) }`,
|
||||
[]testInst{
|
||||
{`C`, []string{`T`}, `interface{chan<- T}`},
|
||||
{`C`, []string{`[]*P`}, `interface{chan<- []*P}`},
|
||||
{`f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func() []int`},
|
||||
},
|
||||
},
|
||||
{`package i0; import "lib"; func _() { lib.F(42) }`,
|
||||
[]testInst{{`F`, []string{`int`}, `func(int)`}},
|
||||
},
|
||||
|
||||
{`package duplfunc0; func f[T any](T) {}; func _() { f(42); f("foo"); f[int](3) }`,
|
||||
[]testInst{
|
||||
{`f`, []string{`int`}, `func(int)`},
|
||||
{`f`, []string{`string`}, `func(string)`},
|
||||
{`f`, []string{`int`}, `func(int)`},
|
||||
},
|
||||
},
|
||||
{`package duplfunc1; import "lib"; func _() { lib.F(42); lib.F("foo"); lib.F(3) }`,
|
||||
[]testInst{
|
||||
{`F`, []string{`int`}, `func(int)`},
|
||||
{`F`, []string{`string`}, `func(string)`},
|
||||
{`F`, []string{`int`}, `func(int)`},
|
||||
},
|
||||
},
|
||||
|
||||
{`package type0; type T[P interface{~int}] struct{ x P }; var _ T[int]`,
|
||||
[]testInst{{`T`, []string{`int`}, `struct{x int}`}},
|
||||
},
|
||||
{`package type1; type T[P interface{~int}] struct{ x P }; var _ (T[int])`,
|
||||
[]testInst{{`T`, []string{`int`}, `struct{x int}`}},
|
||||
},
|
||||
{`package type2; type T[P interface{~int}] struct{ x P }; var _ T[(int)]`,
|
||||
[]testInst{{`T`, []string{`int`}, `struct{x int}`}},
|
||||
},
|
||||
{`package type3; type T[P1 interface{~[]P2}, P2 any] struct{ x P1; y P2 }; var _ T[[]int, int]`,
|
||||
[]testInst{{`T`, []string{`[]int`, `int`}, `struct{x []int; y int}`}},
|
||||
},
|
||||
{`package type4; import "lib"; var _ lib.T[int]`,
|
||||
[]testInst{{`T`, []string{`int`}, `[]int`}},
|
||||
},
|
||||
|
||||
{`package dupltype0; type T[P interface{~int}] struct{ x P }; var x T[int]; var y T[int]`,
|
||||
[]testInst{
|
||||
{`T`, []string{`int`}, `struct{x int}`},
|
||||
{`T`, []string{`int`}, `struct{x int}`},
|
||||
},
|
||||
},
|
||||
{`package dupltype1; type T[P ~int] struct{ x P }; func (r *T[Q]) add(z T[Q]) { r.x += z.x }`,
|
||||
[]testInst{
|
||||
{`T`, []string{`Q`}, `struct{x Q}`},
|
||||
{`T`, []string{`Q`}, `struct{x Q}`},
|
||||
},
|
||||
},
|
||||
{`package dupltype1; import "lib"; var x lib.T[int]; var y lib.T[int]; var z lib.T[string]`,
|
||||
[]testInst{
|
||||
{`T`, []string{`int`}, `[]int`},
|
||||
{`T`, []string{`int`}, `[]int`},
|
||||
{`T`, []string{`string`}, `[]string`},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
imports := make(testImporter)
|
||||
conf := Config{Importer: imports}
|
||||
instances := make(map[*ast.Ident]Instance)
|
||||
uses := make(map[*ast.Ident]Object)
|
||||
instMap := make(map[*ast.Ident]Instance)
|
||||
useMap := make(map[*ast.Ident]Object)
|
||||
makePkg := func(src string) *Package {
|
||||
f, err := parser.ParseFile(fset, "p.go", src, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pkg, err := conf.Check("", fset, []*ast.File{f}, &Info{Instances: instances, Uses: uses})
|
||||
pkg, err := conf.Check("", fset, []*ast.File{f}, &Info{Instances: instMap, Uses: useMap})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -566,60 +584,71 @@ type T[P any] []P
|
||||
makePkg(lib)
|
||||
pkg := makePkg(test.src)
|
||||
|
||||
// look for instance information
|
||||
var targs []Type
|
||||
var typ Type
|
||||
for ident, inst := range instances {
|
||||
if ExprString(ident) == test.name {
|
||||
for i := 0; i < inst.TypeArgs.Len(); i++ {
|
||||
targs = append(targs, inst.TypeArgs.At(i))
|
||||
}
|
||||
typ = inst.Type
|
||||
t.Run(pkg.Name(), func(t *testing.T) {
|
||||
// Sort instances in source order for stability.
|
||||
instances := sortedInstances(instMap)
|
||||
if got, want := len(instances), len(test.instances); got != want {
|
||||
t.Fatalf("got %d instances, want %d", got, want)
|
||||
}
|
||||
|
||||
// Check that we can find the corresponding parameterized type.
|
||||
ptype := uses[ident].Type()
|
||||
// Pairwise compare with the expected instances.
|
||||
for ii, inst := range instances {
|
||||
var targs []Type
|
||||
for i := 0; i < inst.Inst.TypeArgs.Len(); i++ {
|
||||
targs = append(targs, inst.Inst.TypeArgs.At(i))
|
||||
}
|
||||
typ := inst.Inst.Type
|
||||
|
||||
testInst := test.instances[ii]
|
||||
if got := inst.Ident.Name; got != testInst.name {
|
||||
t.Fatalf("got name %s, want %s", got, testInst.name)
|
||||
}
|
||||
if len(targs) != len(testInst.targs) {
|
||||
t.Fatalf("got %d type arguments; want %d", len(targs), len(testInst.targs))
|
||||
}
|
||||
for i, targ := range targs {
|
||||
if got := targ.String(); got != testInst.targs[i] {
|
||||
t.Errorf("type argument %d: got %s; want %s", i, got, testInst.targs[i])
|
||||
}
|
||||
}
|
||||
if got := typ.Underlying().String(); got != testInst.typ {
|
||||
t.Errorf("package %s: got %s; want %s", pkg.Name(), got, testInst.typ)
|
||||
}
|
||||
|
||||
// Verify the invariant that re-instantiating the corresponding generic
|
||||
// type with TypeArgs results in an identical instance.
|
||||
ptype := useMap[inst.Ident].Type()
|
||||
lister, _ := ptype.(interface{ TypeParams() *TypeParamList })
|
||||
if lister == nil || lister.TypeParams().Len() == 0 {
|
||||
t.Errorf("package %s: info.Types[%v] = %v, want parameterized type", pkg.Name(), ident, ptype)
|
||||
continue
|
||||
t.Fatalf("info.Types[%v] = %v, want parameterized type", inst.Ident, ptype)
|
||||
}
|
||||
|
||||
// Verify the invariant that re-instantiating the generic type with
|
||||
// TypeArgs results in an equivalent type.
|
||||
inst2, err := Instantiate(nil, ptype, targs, true)
|
||||
if err != nil {
|
||||
t.Errorf("Instantiate(%v, %v) failed: %v", ptype, targs, err)
|
||||
}
|
||||
if !Identical(inst.Type, inst2) {
|
||||
t.Errorf("%v and %v are not identical", inst.Type, inst2)
|
||||
if !Identical(inst.Inst.Type, inst2) {
|
||||
t.Errorf("%v and %v are not identical", inst.Inst.Type, inst2)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if targs == nil {
|
||||
t.Errorf("package %s: no instance information found for %s", pkg.Name(), test.name)
|
||||
continue
|
||||
}
|
||||
|
||||
// check that type arguments are correct
|
||||
if len(targs) != len(test.targs) {
|
||||
t.Errorf("package %s: got %d type arguments; want %d", pkg.Name(), len(targs), len(test.targs))
|
||||
continue
|
||||
}
|
||||
for i, targ := range targs {
|
||||
if got := targ.String(); got != test.targs[i] {
|
||||
t.Errorf("package %s, %d. type argument: got %s; want %s", pkg.Name(), i, got, test.targs[i])
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// check that the types match
|
||||
if got := typ.Underlying().String(); got != test.typ {
|
||||
t.Errorf("package %s: got %s; want %s", pkg.Name(), got, test.typ)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type recordedInstance struct {
|
||||
Ident *ast.Ident
|
||||
Inst Instance
|
||||
}
|
||||
|
||||
func sortedInstances(m map[*ast.Ident]Instance) (instances []recordedInstance) {
|
||||
for id, inst := range m {
|
||||
instances = append(instances, recordedInstance{id, inst})
|
||||
}
|
||||
sort.Slice(instances, func(i, j int) bool {
|
||||
return instances[i].Ident.Pos() < instances[j].Ident.Pos()
|
||||
})
|
||||
return instances
|
||||
}
|
||||
|
||||
func TestDefsInfo(t *testing.T) {
|
||||
var tests = []struct {
|
||||
src string
|
||||
@@ -1688,7 +1717,7 @@ func F(){
|
||||
var F = /*F=func:12*/ F /*F=var:17*/ ; _ = F
|
||||
|
||||
var a []int
|
||||
for i, x := range /*i=undef*/ /*x=var:16*/ a /*i=var:20*/ /*x=var:20*/ { _ = i; _ = x }
|
||||
for i, x := range a /*i=undef*/ /*x=var:16*/ { _ = i; _ = x }
|
||||
|
||||
var i interface{}
|
||||
switch y := i.(type) { /*y=undef*/
|
||||
|
||||
@@ -429,7 +429,7 @@ var cgoPrefixes = [...]string{
|
||||
"_Cmacro_", // function to evaluate the expanded expression
|
||||
}
|
||||
|
||||
func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
|
||||
func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *Named) {
|
||||
// these must be declared before the "goto Error" statements
|
||||
var (
|
||||
obj Object
|
||||
@@ -528,6 +528,12 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
|
||||
|
||||
check.exprOrType(x, e.X, false)
|
||||
switch x.mode {
|
||||
case typexpr:
|
||||
// don't crash for "type T T.x" (was issue #51509)
|
||||
if def != nil && x.typ == def {
|
||||
check.cycleError([]Object{def.obj})
|
||||
goto Error
|
||||
}
|
||||
case builtin:
|
||||
// types2 uses the position of '.' for the error
|
||||
check.errorf(e.Sel, _UncalledBuiltin, "cannot select on %s", x)
|
||||
|
||||
@@ -1339,11 +1339,6 @@ const (
|
||||
// func _() {
|
||||
// f()
|
||||
// }
|
||||
//
|
||||
// Example:
|
||||
// type N[P, Q any] struct{}
|
||||
//
|
||||
// var _ N[int]
|
||||
_CannotInferTypeArgs
|
||||
|
||||
// _InvalidTypeArg occurs when a type argument does not satisfy its
|
||||
|
||||
@@ -37,8 +37,8 @@ func Eval(fset *token.FileSet, pkg *Package, pos token.Pos, expr string) (_ Type
|
||||
|
||||
// CheckExpr type checks the expression expr as if it had appeared at position
|
||||
// pos of package pkg. Type information about the expression is recorded in
|
||||
// info. The expression may be an uninstantiated parameterized function or
|
||||
// type.
|
||||
// info. The expression may be an identifier denoting an uninstantiated generic
|
||||
// function or type.
|
||||
//
|
||||
// If pkg == nil, the Universe scope is used and the provided
|
||||
// position pos is ignored. If pkg != nil, and pos is invalid,
|
||||
|
||||
@@ -1533,7 +1533,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||
return kind
|
||||
|
||||
case *ast.SelectorExpr:
|
||||
check.selector(x, e)
|
||||
check.selector(x, e, nil)
|
||||
|
||||
case *ast.IndexExpr, *ast.IndexListExpr:
|
||||
ix := typeparams.UnpackIndexExpr(e)
|
||||
@@ -1588,6 +1588,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||
case invalid:
|
||||
goto Error
|
||||
case typexpr:
|
||||
check.validVarType(e.X, x.typ)
|
||||
x.typ = &Pointer{base: x.typ}
|
||||
default:
|
||||
var base Type
|
||||
|
||||
@@ -487,21 +487,88 @@ func (check *Checker) inferB(posn positioner, tparams []*TypeParam, targs []Type
|
||||
}
|
||||
}
|
||||
|
||||
// If a constraint has a core type, unify the corresponding type parameter with it.
|
||||
for _, tpar := range tparams {
|
||||
if ctype := adjCoreType(tpar); ctype != nil {
|
||||
if !u.unify(tpar, ctype) {
|
||||
// TODO(gri) improve error message by providing the type arguments
|
||||
// which we know already
|
||||
check.errorf(posn, _InvalidTypeArg, "%s does not match %s", tpar, ctype)
|
||||
return nil, 0
|
||||
// Repeatedly apply constraint type inference as long as
|
||||
// there are still unknown type arguments and progress is
|
||||
// being made.
|
||||
//
|
||||
// This is an O(n^2) algorithm where n is the number of
|
||||
// type parameters: if there is progress (and iteration
|
||||
// continues), at least one type argument is inferred
|
||||
// per iteration and we have a doubly nested loop.
|
||||
// In practice this is not a problem because the number
|
||||
// of type parameters tends to be very small (< 5 or so).
|
||||
// (It should be possible for unification to efficiently
|
||||
// signal newly inferred type arguments; then the loops
|
||||
// here could handle the respective type parameters only,
|
||||
// but that will come at a cost of extra complexity which
|
||||
// may not be worth it.)
|
||||
for n := u.x.unknowns(); n > 0; {
|
||||
nn := n
|
||||
|
||||
for i, tpar := range tparams {
|
||||
// If there is a core term (i.e., a core type with tilde information)
|
||||
// unify the type parameter with the core type.
|
||||
if core, single := coreTerm(tpar); core != nil {
|
||||
// A type parameter can be unified with its core type in two cases.
|
||||
tx := u.x.at(i)
|
||||
switch {
|
||||
case tx != nil:
|
||||
// The corresponding type argument tx is known.
|
||||
// In this case, if the core type has a tilde, the type argument's underlying
|
||||
// type must match the core type, otherwise the type argument and the core type
|
||||
// must match.
|
||||
// If tx is an external type parameter, don't consider its underlying type
|
||||
// (which is an interface). Core type unification will attempt to unify against
|
||||
// core.typ.
|
||||
// Note also that even with inexact unification we cannot leave away the under
|
||||
// call here because it's possible that both tx and core.typ are named types,
|
||||
// with under(tx) being a (named) basic type matching core.typ. Such cases do
|
||||
// not match with inexact unification.
|
||||
if core.tilde && !isTypeParam(tx) {
|
||||
tx = under(tx)
|
||||
}
|
||||
if !u.unify(tx, core.typ) {
|
||||
// TODO(gri) improve error message by providing the type arguments
|
||||
// which we know already
|
||||
// Don't use term.String() as it always qualifies types, even if they
|
||||
// are in the current package.
|
||||
tilde := ""
|
||||
if core.tilde {
|
||||
tilde = "~"
|
||||
}
|
||||
check.errorf(posn, _InvalidTypeArg, "%s does not match %s%s", tpar, tilde, core.typ)
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
case single && !core.tilde:
|
||||
// The corresponding type argument tx is unknown and there's a single
|
||||
// specific type and no tilde.
|
||||
// In this case the type argument must be that single type; set it.
|
||||
u.x.set(i, core.typ)
|
||||
|
||||
default:
|
||||
// Unification is not possible and no progress was made.
|
||||
continue
|
||||
}
|
||||
|
||||
// The number of known type arguments may have changed.
|
||||
nn = u.x.unknowns()
|
||||
if nn == 0 {
|
||||
break // all type arguments are known
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(nn <= n)
|
||||
if nn == n {
|
||||
break // no progress
|
||||
}
|
||||
n = nn
|
||||
}
|
||||
|
||||
// u.x.types() now contains the incoming type arguments plus any additional type
|
||||
// arguments which were inferred from core types. The newly inferred non-
|
||||
// nil entries may still contain references to other type parameters.
|
||||
// arguments which were inferred from core terms. The newly inferred non-nil
|
||||
// entries may still contain references to other type parameters.
|
||||
// For instance, for [A any, B interface{ []C }, C interface{ *A }], if A == int
|
||||
// was given, unification produced the type list [int, []C, *A]. We eliminate the
|
||||
// remaining type parameters by substituting the type parameters in this type list
|
||||
@@ -590,26 +657,40 @@ func (check *Checker) inferB(posn positioner, tparams []*TypeParam, targs []Type
|
||||
return
|
||||
}
|
||||
|
||||
// adjCoreType returns the core type of tpar unless the
|
||||
// type parameter embeds a single, possibly named type,
|
||||
// in which case it returns that single type instead.
|
||||
// (The core type is always the underlying type of that
|
||||
// single type.)
|
||||
func adjCoreType(tpar *TypeParam) Type {
|
||||
var single *term
|
||||
if tpar.is(func(t *term) bool {
|
||||
if single == nil && t != nil {
|
||||
single = t
|
||||
return true
|
||||
// If the type parameter has a single specific type S, coreTerm returns (S, true).
|
||||
// Otherwise, if tpar has a core type T, it returns a term corresponding to that
|
||||
// core type and false. In that case, if any term of tpar has a tilde, the core
|
||||
// term has a tilde. In all other cases coreTerm returns (nil, false).
|
||||
func coreTerm(tpar *TypeParam) (*term, bool) {
|
||||
n := 0
|
||||
var single *term // valid if n == 1
|
||||
var tilde bool
|
||||
tpar.is(func(t *term) bool {
|
||||
if t == nil {
|
||||
assert(n == 0)
|
||||
return false // no terms
|
||||
}
|
||||
return false // zero or more than one terms
|
||||
}) {
|
||||
n++
|
||||
single = t
|
||||
if t.tilde {
|
||||
tilde = true
|
||||
}
|
||||
return true
|
||||
})
|
||||
if n == 1 {
|
||||
if debug {
|
||||
assert(under(single.typ) == coreType(tpar))
|
||||
assert(debug && under(single.typ) == coreType(tpar))
|
||||
}
|
||||
return single.typ
|
||||
return single, true
|
||||
}
|
||||
return coreType(tpar)
|
||||
if typ := coreType(tpar); typ != nil {
|
||||
// A core type is always an underlying type.
|
||||
// If any term of tpar has a tilde, we don't
|
||||
// have a precise core type and we must return
|
||||
// a tilde as well.
|
||||
return &term{tilde, typ}, false
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
type cycleFinder struct {
|
||||
@@ -657,8 +738,6 @@ func (w *cycleFinder) typ(typ Type) {
|
||||
// in signatures where they are handled explicitly.
|
||||
|
||||
case *Signature:
|
||||
// There are no "method types" so we should never see a recv.
|
||||
assert(t.recv == nil)
|
||||
if t.params != nil {
|
||||
w.varList(t.params.vars)
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@ import (
|
||||
|
||||
// Instantiate instantiates the type orig with the given type arguments targs.
|
||||
// orig must be a *Named or a *Signature type. If there is no error, the
|
||||
// resulting Type is a new, instantiated (not parameterized) type of the same
|
||||
// kind (either a *Named or a *Signature). Methods attached to a *Named type
|
||||
// are also instantiated, and associated with a new *Func that has the same
|
||||
// position as the original method, but nil function scope.
|
||||
// resulting Type is an instantiated type of the same kind (either a *Named or
|
||||
// a *Signature). Methods attached to a *Named type are also instantiated, and
|
||||
// associated with a new *Func that has the same position as the original
|
||||
// method, but nil function scope.
|
||||
//
|
||||
// If ctxt is non-nil, it may be used to de-duplicate the instance against
|
||||
// previous instances with the same identity. As a special case, generic
|
||||
|
||||
@@ -70,7 +70,8 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
|
||||
// see if there is a matching field (but not a method, those need to be declared
|
||||
// explicitly in the constraint). If the constraint is a named pointer type (see
|
||||
// above), we are ok here because only fields are accepted as results.
|
||||
if obj == nil && isTypeParam(T) {
|
||||
const enableTParamFieldLookup = false // see issue #51576
|
||||
if enableTParamFieldLookup && obj == nil && isTypeParam(T) {
|
||||
if t := coreType(T); t != nil {
|
||||
obj, index, indirect = lookupFieldOrMethod(t, addressable, pkg, name, false)
|
||||
if _, ok := obj.(*Var); !ok {
|
||||
|
||||
@@ -98,12 +98,12 @@ func (t *Named) cleanup() {
|
||||
}
|
||||
|
||||
// Obj returns the type name for the declaration defining the named type t. For
|
||||
// instantiated types, this is the type name of the base type.
|
||||
// instantiated types, this is same as the type name of the origin type.
|
||||
func (t *Named) Obj() *TypeName {
|
||||
return t.orig.obj // for non-instances this is the same as t.obj
|
||||
}
|
||||
|
||||
// Origin returns the parameterized type from which the named type t is
|
||||
// Origin returns the generic type from which the named type t is
|
||||
// instantiated. If t is not an instantiated type, the result is t.
|
||||
func (t *Named) Origin() *Named { return t.orig }
|
||||
|
||||
@@ -111,7 +111,7 @@ func (t *Named) Origin() *Named { return t.orig }
|
||||
// between parameterized instantiated and non-instantiated types.
|
||||
|
||||
// TypeParams returns the type parameters of the named type t, or nil.
|
||||
// The result is non-nil for an (originally) parameterized type even if it is instantiated.
|
||||
// The result is non-nil for an (originally) generic type even if it is instantiated.
|
||||
func (t *Named) TypeParams() *TypeParamList { return t.resolve(nil).tparams }
|
||||
|
||||
// SetTypeParams sets the type parameters of the named type t.
|
||||
@@ -124,7 +124,11 @@ func (t *Named) SetTypeParams(tparams []*TypeParam) {
|
||||
// TypeArgs returns the type arguments used to instantiate the named type t.
|
||||
func (t *Named) TypeArgs() *TypeList { return t.targs }
|
||||
|
||||
// NumMethods returns the number of explicit methods whose receiver is named type t.
|
||||
// NumMethods returns the number of explicit methods defined for t.
|
||||
//
|
||||
// For an ordinary or instantiated type t, the receiver base type of these
|
||||
// methods will be the named type t. For an uninstantiated generic type t, each
|
||||
// method receiver will be instantiated with its receiver type parameters.
|
||||
func (t *Named) NumMethods() int { return t.resolve(nil).methods.Len() }
|
||||
|
||||
// Method returns the i'th method of named type t for 0 <= i < t.NumMethods().
|
||||
|
||||
@@ -821,8 +821,6 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
||||
|
||||
case *ast.RangeStmt:
|
||||
inner |= breakOk | continueOk
|
||||
check.openScope(s, "for")
|
||||
defer check.closeScope()
|
||||
|
||||
// check expression to iterate over
|
||||
var x operand
|
||||
@@ -857,6 +855,11 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
||||
}
|
||||
}
|
||||
|
||||
// Open the for-statement block scope now, after the range clause.
|
||||
// Iteration variables declared with := need to go in this scope (was issue #51437).
|
||||
check.openScope(s, "range")
|
||||
defer check.closeScope()
|
||||
|
||||
// check assignment to/declaration of iteration variables
|
||||
// (irregular assignment, cannot easily map to existing assignment checks)
|
||||
|
||||
@@ -865,9 +868,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
||||
rhs := [2]Type{key, val} // key, val may be nil
|
||||
|
||||
if s.Tok == token.DEFINE {
|
||||
// short variable declaration; variable scope starts after the range clause
|
||||
// (the for loop opens a new scope, so variables on the lhs never redeclare
|
||||
// previously declared variables)
|
||||
// short variable declaration
|
||||
var vars []*Var
|
||||
for i, lhs := range lhs {
|
||||
if lhs == nil {
|
||||
@@ -904,12 +905,8 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
||||
|
||||
// declare variables
|
||||
if len(vars) > 0 {
|
||||
scopePos := s.X.End()
|
||||
scopePos := s.Body.Pos()
|
||||
for _, obj := range vars {
|
||||
// spec: "The scope of a constant or variable identifier declared inside
|
||||
// a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
|
||||
// for short variable declarations) and ends at the end of the innermost
|
||||
// containing block."
|
||||
check.declare(check.scope, nil /* recordDef already called */, obj, scopePos)
|
||||
}
|
||||
} else {
|
||||
|
||||
12
src/go/types/testdata/check/funcinference.go2
vendored
12
src/go/types/testdata/check/funcinference.go2
vendored
@@ -8,21 +8,21 @@ import "strconv"
|
||||
|
||||
type any interface{}
|
||||
|
||||
func f0[A any, B interface{~*C}, C interface{~*D}, D interface{~*A}](A, B, C, D) {}
|
||||
func f0[A any, B interface{*C}, C interface{*D}, D interface{*A}](A, B, C, D) {}
|
||||
func _() {
|
||||
f := f0[string]
|
||||
f("a", nil, nil, nil)
|
||||
f0("a", nil, nil, nil)
|
||||
}
|
||||
|
||||
func f1[A any, B interface{~*A}](A, B) {}
|
||||
func f1[A any, B interface{*A}](A, B) {}
|
||||
func _() {
|
||||
f := f1[int]
|
||||
f(int(0), new(int))
|
||||
f1(int(0), new(int))
|
||||
}
|
||||
|
||||
func f2[A any, B interface{~[]A}](A, B) {}
|
||||
func f2[A any, B interface{[]A}](A, B) {}
|
||||
func _() {
|
||||
f := f2[byte]
|
||||
f(byte(0), []byte{})
|
||||
@@ -38,7 +38,7 @@ func _() {
|
||||
// f3(x, &x, &x)
|
||||
// }
|
||||
|
||||
func f4[A any, B interface{~[]C}, C interface{~*A}](A, B, C) {}
|
||||
func f4[A any, B interface{[]C}, C interface{*A}](A, B, C) {}
|
||||
func _() {
|
||||
f := f4[int]
|
||||
var x int
|
||||
@@ -46,7 +46,7 @@ func _() {
|
||||
f4(x, []*int{}, &x)
|
||||
}
|
||||
|
||||
func f5[A interface{~struct{b B; c C}}, B any, C interface{~*B}](x B) A { panic(0) }
|
||||
func f5[A interface{struct{b B; c C}}, B any, C interface{*B}](x B) A { panic(0) }
|
||||
func _() {
|
||||
x := f5(1.2)
|
||||
var _ float64 = x.b
|
||||
@@ -79,7 +79,7 @@ var _ = Double(MySlice{1})
|
||||
|
||||
type Setter[B any] interface {
|
||||
Set(string)
|
||||
~*B
|
||||
*B
|
||||
}
|
||||
|
||||
func FromStrings[T interface{}, PT Setter[T]](s []string) []T {
|
||||
|
||||
36
src/go/types/testdata/check/typeinference.go2
vendored
36
src/go/types/testdata/check/typeinference.go2
vendored
@@ -4,44 +4,46 @@
|
||||
|
||||
package typeInference
|
||||
|
||||
// As of issue #51527, type-type inference has been disabled.
|
||||
|
||||
// basic inference
|
||||
type Tb[P ~*Q, Q any] int
|
||||
func _() {
|
||||
var x Tb[*int]
|
||||
var x Tb /* ERROR got 1 arguments */ [*int]
|
||||
var y Tb[*int, int]
|
||||
x = y
|
||||
x = y /* ERROR cannot use y .* in assignment */
|
||||
_ = x
|
||||
}
|
||||
|
||||
// recursive inference
|
||||
type Tr[A any, B ~*C, C ~*D, D ~*A] int
|
||||
type Tr[A any, B *C, C *D, D *A] int
|
||||
func _() {
|
||||
var x Tr[string]
|
||||
var x Tr /* ERROR got 1 arguments */ [string]
|
||||
var y Tr[string, ***string, **string, *string]
|
||||
var z Tr[int, ***int, **int, *int]
|
||||
x = y
|
||||
x = y /* ERROR cannot use y .* in assignment */
|
||||
x = z // ERROR cannot use z .* as Tr
|
||||
_ = x
|
||||
}
|
||||
|
||||
// other patterns of inference
|
||||
type To0[A any, B ~[]A] int
|
||||
type To1[A any, B ~struct{a A}] int
|
||||
type To2[A any, B ~[][]A] int
|
||||
type To3[A any, B ~[3]*A] int
|
||||
type To4[A any, B any, C ~struct{a A; b B}] int
|
||||
type To0[A any, B []A] int
|
||||
type To1[A any, B struct{a A}] int
|
||||
type To2[A any, B [][]A] int
|
||||
type To3[A any, B [3]*A] int
|
||||
type To4[A any, B any, C struct{a A; b B}] int
|
||||
func _() {
|
||||
var _ To0[int]
|
||||
var _ To1[int]
|
||||
var _ To2[int]
|
||||
var _ To3[int]
|
||||
var _ To4[int, string]
|
||||
var _ To0 /* ERROR got 1 arguments */ [int]
|
||||
var _ To1 /* ERROR got 1 arguments */ [int]
|
||||
var _ To2 /* ERROR got 1 arguments */ [int]
|
||||
var _ To3 /* ERROR got 1 arguments */ [int]
|
||||
var _ To4 /* ERROR got 2 arguments */ [int, string]
|
||||
}
|
||||
|
||||
// failed inference
|
||||
type Tf0[A, B any] int
|
||||
type Tf1[A any, B ~struct{a A; c C}, C any] int
|
||||
func _() {
|
||||
var _ Tf0 /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type parameters */ [int]
|
||||
var _ Tf1 /* ERROR cannot infer B */ /* ERROR got 1 arguments but 3 type parameters */ [int]
|
||||
var _ Tf0 /* ERROR got 1 arguments but 2 type parameters */ [int]
|
||||
var _ Tf1 /* ERROR got 1 arguments but 3 type parameters */ [int]
|
||||
}
|
||||
|
||||
18
src/go/types/testdata/examples/inference.go2
vendored
18
src/go/types/testdata/examples/inference.go2
vendored
@@ -78,7 +78,7 @@ func _() {
|
||||
related1(si, "foo" /* ERROR cannot use "foo" */ )
|
||||
}
|
||||
|
||||
func related2[Elem any, Slice interface{~[]Elem}](e Elem, s Slice) {}
|
||||
func related2[Elem any, Slice interface{[]Elem}](e Elem, s Slice) {}
|
||||
|
||||
func _() {
|
||||
// related2 can be called with explicit instantiation.
|
||||
@@ -109,16 +109,8 @@ func _() {
|
||||
related3[int, []int]()
|
||||
related3[byte, List[byte]]()
|
||||
|
||||
// Alternatively, the 2nd type argument can be inferred
|
||||
// from the first one through constraint type inference.
|
||||
related3[int]()
|
||||
|
||||
// The inferred type is the core type of the Slice
|
||||
// type parameter.
|
||||
var _ []int = related3[int]()
|
||||
|
||||
// It is not the defined parameterized type List.
|
||||
type anotherList []float32
|
||||
var _ anotherList = related3[float32]() // valid
|
||||
var _ anotherList = related3 /* ERROR cannot use .* \(value of type List\[float32\]\) as anotherList */ [float32, List[float32]]()
|
||||
// The 2nd type argument cannot be inferred from the first
|
||||
// one because there's two possible choices: []Elem and
|
||||
// List[Elem].
|
||||
related3 /* ERROR cannot infer Slice */ [int]()
|
||||
}
|
||||
|
||||
2
src/go/types/testdata/examples/typesets.go2
vendored
2
src/go/types/testdata/examples/typesets.go2
vendored
@@ -35,7 +35,7 @@ func _() int {
|
||||
return deref(p)
|
||||
}
|
||||
|
||||
func addrOfCopy[V any, P ~*V](v V) P {
|
||||
func addrOfCopy[V any, P *V](v V) P {
|
||||
return &v
|
||||
}
|
||||
|
||||
|
||||
10
src/go/types/testdata/fixedbugs/issue41124.go2
vendored
10
src/go/types/testdata/fixedbugs/issue41124.go2
vendored
@@ -47,7 +47,7 @@ type _ struct{
|
||||
}
|
||||
|
||||
type _ struct{
|
||||
I3 // ERROR interface is .* comparable
|
||||
I3 // ERROR interface contains type constraints
|
||||
}
|
||||
|
||||
// General composite types.
|
||||
@@ -59,19 +59,19 @@ type (
|
||||
_ []I1 // ERROR interface is .* comparable
|
||||
_ []I2 // ERROR interface contains type constraints
|
||||
|
||||
_ *I3 // ERROR interface is .* comparable
|
||||
_ *I3 // ERROR interface contains type constraints
|
||||
_ map[I1 /* ERROR interface is .* comparable */ ]I2 // ERROR interface contains type constraints
|
||||
_ chan I3 // ERROR interface is .* comparable
|
||||
_ chan I3 // ERROR interface contains type constraints
|
||||
_ func(I1 /* ERROR interface is .* comparable */ )
|
||||
_ func() I2 // ERROR interface contains type constraints
|
||||
)
|
||||
|
||||
// Other cases.
|
||||
|
||||
var _ = [...]I3 /* ERROR interface is .* comparable */ {}
|
||||
var _ = [...]I3 /* ERROR interface contains type constraints */ {}
|
||||
|
||||
func _(x interface{}) {
|
||||
_ = x.(I3 /* ERROR interface is .* comparable */ )
|
||||
_ = x.(I3 /* ERROR interface contains type constraints */ )
|
||||
}
|
||||
|
||||
type T1[_ any] struct{}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
package p
|
||||
|
||||
func f[F interface{~*Q}, G interface{~*R}, Q, R any](q Q, r R) {}
|
||||
func f[F interface{*Q}, G interface{*R}, Q, R any](q Q, r R) {}
|
||||
|
||||
func _() {
|
||||
f[*float64, *int](1, 2)
|
||||
|
||||
@@ -10,9 +10,10 @@ type S[A, B any] struct {
|
||||
|
||||
func (S[A, B]) m() {}
|
||||
|
||||
// TODO(gri) We should only report one error below. See issue #50588.
|
||||
// TODO(gri): with type-type inference enabled we should only report one error
|
||||
// below. See issue #50588.
|
||||
|
||||
func _[A any](s S /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type parameters */ [A]) {
|
||||
func _[A any](s S /* ERROR got 1 arguments but 2 type parameters */ [A]) {
|
||||
// we should see no follow-on errors below
|
||||
s.f = 1
|
||||
s.m()
|
||||
@@ -21,7 +22,7 @@ func _[A any](s S /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type
|
||||
// another test case from the issue
|
||||
|
||||
func _() {
|
||||
X(Interface[*F /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type parameters */ [string]](Impl{}))
|
||||
X(Interface[*F /* ERROR got 1 arguments but 2 type parameters */ [string]](Impl{}))
|
||||
}
|
||||
|
||||
func X[Q Qer](fs Interface[Q]) {
|
||||
|
||||
24
src/go/types/testdata/fixedbugs/issue50417.go2
vendored
24
src/go/types/testdata/fixedbugs/issue50417.go2
vendored
@@ -2,6 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Field accesses through type parameters are disabled
|
||||
// until we have a more thorough understanding of the
|
||||
// implications on the spec. See issue #51576.
|
||||
|
||||
package p
|
||||
|
||||
type Sf struct {
|
||||
@@ -9,13 +13,13 @@ type Sf struct {
|
||||
}
|
||||
|
||||
func f0[P Sf](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
_ = p.f // ERROR p\.f undefined
|
||||
p.f /* ERROR p\.f undefined */ = 0
|
||||
}
|
||||
|
||||
func f0t[P ~struct{f int}](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
_ = p.f // ERROR p\.f undefined
|
||||
p.f /* ERROR p\.f undefined */ = 0
|
||||
}
|
||||
|
||||
var _ = f0[Sf]
|
||||
@@ -25,8 +29,8 @@ var _ = f0[Sm /* ERROR does not implement */ ]
|
||||
var _ = f0t[Sm /* ERROR does not implement */ ]
|
||||
|
||||
func f1[P interface{ Sf; m() }](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
_ = p.f // ERROR p\.f undefined
|
||||
p.f /* ERROR p\.f undefined */ = 0
|
||||
p.m()
|
||||
}
|
||||
|
||||
@@ -44,8 +48,8 @@ type Sfm struct {
|
||||
func (Sfm) m() {}
|
||||
|
||||
func f2[P interface{ Sfm; m() }](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
_ = p.f // ERROR p\.f undefined
|
||||
p.f /* ERROR p\.f undefined */ = 0
|
||||
p.m()
|
||||
}
|
||||
|
||||
@@ -56,8 +60,8 @@ var _ = f2[Sfm]
|
||||
type PSfm *Sfm
|
||||
|
||||
func f3[P interface{ PSfm }](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
_ = p.f // ERROR p\.f undefined
|
||||
p.f /* ERROR p\.f undefined */ = 0
|
||||
p.m /* ERROR type P has no field or method m */ ()
|
||||
}
|
||||
|
||||
|
||||
13
src/go/types/testdata/fixedbugs/issue50782.go2
vendored
13
src/go/types/testdata/fixedbugs/issue50782.go2
vendored
@@ -2,6 +2,10 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Field accesses through type parameters are disabled
|
||||
// until we have a more thorough understanding of the
|
||||
// implications on the spec. See issue #51576.
|
||||
|
||||
package p
|
||||
|
||||
// The first example from the issue.
|
||||
@@ -18,9 +22,12 @@ type numericAbs[T Numeric] interface {
|
||||
// AbsDifference computes the absolute value of the difference of
|
||||
// a and b, where the absolute value is determined by the Abs method.
|
||||
func absDifference[T numericAbs[T /* ERROR T does not implement Numeric */]](a, b T) T {
|
||||
// TODO: the error below should probably be positioned on the '-'.
|
||||
d := a /* ERROR "invalid operation: operator - not defined" */ .Value - b.Value
|
||||
return d.Abs()
|
||||
// Field accesses are not permitted for now. Keep an error so
|
||||
// we can find and fix this code once the situation changes.
|
||||
return a.Value // ERROR a\.Value undefined
|
||||
// TODO: The error below should probably be positioned on the '-'.
|
||||
// d := a /* ERROR "invalid operation: operator - not defined" */ .Value - b.Value
|
||||
// return d.Abs()
|
||||
}
|
||||
|
||||
// The second example from the issue.
|
||||
|
||||
@@ -16,7 +16,7 @@ func G[A, B any](F[A, B]) {
|
||||
|
||||
func _() {
|
||||
// TODO(gri) only report one error below (issue #50932)
|
||||
var x F /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type parameters */ [int]
|
||||
var x F /* ERROR got 1 arguments but 2 type parameters */ [int]
|
||||
G(x /* ERROR does not match */)
|
||||
}
|
||||
|
||||
@@ -46,9 +46,9 @@ func NSG[G any](c RSC[G]) {
|
||||
fmt.Println(c)
|
||||
}
|
||||
|
||||
func MMD[Rc RC /* ERROR cannot infer RG */ /* ERROR got 1 arguments */ [RG], RG any, G any]() M /* ERROR got 2 arguments */ /* ERROR Rc does not match */ [Rc, RG] {
|
||||
func MMD[Rc RC /* ERROR got 1 arguments */ [RG], RG any, G any]() M /* ERROR got 2 arguments */ [Rc, RG] {
|
||||
|
||||
var nFn NFn /* ERROR got 2 arguments */ /* ERROR Rc does not match */ [Rc, RG]
|
||||
var nFn NFn /* ERROR got 2 arguments */ [Rc, RG]
|
||||
|
||||
var empty Rc
|
||||
switch any(empty).(type) {
|
||||
|
||||
164
src/go/types/testdata/fixedbugs/issue51229.go2
vendored
Normal file
164
src/go/types/testdata/fixedbugs/issue51229.go2
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
// Copyright 2022 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
|
||||
|
||||
// Constraint type inference should be independent of the
|
||||
// ordering of the type parameter declarations. Try all
|
||||
// permutations in the test case below.
|
||||
// Permutations produced by https://go.dev/play/p/PHcZNGJTEBZ.
|
||||
|
||||
func f00[S1 ~[]E1, S2 ~[]E2, E1 ~byte, E2 ~byte](S1, S2) {}
|
||||
func f01[S2 ~[]E2, S1 ~[]E1, E1 ~byte, E2 ~byte](S1, S2) {}
|
||||
func f02[E1 ~byte, S1 ~[]E1, S2 ~[]E2, E2 ~byte](S1, S2) {}
|
||||
func f03[S1 ~[]E1, E1 ~byte, S2 ~[]E2, E2 ~byte](S1, S2) {}
|
||||
func f04[S2 ~[]E2, E1 ~byte, S1 ~[]E1, E2 ~byte](S1, S2) {}
|
||||
func f05[E1 ~byte, S2 ~[]E2, S1 ~[]E1, E2 ~byte](S1, S2) {}
|
||||
func f06[E2 ~byte, S2 ~[]E2, S1 ~[]E1, E1 ~byte](S1, S2) {}
|
||||
func f07[S2 ~[]E2, E2 ~byte, S1 ~[]E1, E1 ~byte](S1, S2) {}
|
||||
func f08[S1 ~[]E1, E2 ~byte, S2 ~[]E2, E1 ~byte](S1, S2) {}
|
||||
func f09[E2 ~byte, S1 ~[]E1, S2 ~[]E2, E1 ~byte](S1, S2) {}
|
||||
func f10[S2 ~[]E2, S1 ~[]E1, E2 ~byte, E1 ~byte](S1, S2) {}
|
||||
func f11[S1 ~[]E1, S2 ~[]E2, E2 ~byte, E1 ~byte](S1, S2) {}
|
||||
func f12[S1 ~[]E1, E1 ~byte, E2 ~byte, S2 ~[]E2](S1, S2) {}
|
||||
func f13[E1 ~byte, S1 ~[]E1, E2 ~byte, S2 ~[]E2](S1, S2) {}
|
||||
func f14[E2 ~byte, S1 ~[]E1, E1 ~byte, S2 ~[]E2](S1, S2) {}
|
||||
func f15[S1 ~[]E1, E2 ~byte, E1 ~byte, S2 ~[]E2](S1, S2) {}
|
||||
func f16[E1 ~byte, E2 ~byte, S1 ~[]E1, S2 ~[]E2](S1, S2) {}
|
||||
func f17[E2 ~byte, E1 ~byte, S1 ~[]E1, S2 ~[]E2](S1, S2) {}
|
||||
func f18[E2 ~byte, E1 ~byte, S2 ~[]E2, S1 ~[]E1](S1, S2) {}
|
||||
func f19[E1 ~byte, E2 ~byte, S2 ~[]E2, S1 ~[]E1](S1, S2) {}
|
||||
func f20[S2 ~[]E2, E2 ~byte, E1 ~byte, S1 ~[]E1](S1, S2) {}
|
||||
func f21[E2 ~byte, S2 ~[]E2, E1 ~byte, S1 ~[]E1](S1, S2) {}
|
||||
func f22[E1 ~byte, S2 ~[]E2, E2 ~byte, S1 ~[]E1](S1, S2) {}
|
||||
func f23[S2 ~[]E2, E1 ~byte, E2 ~byte, S1 ~[]E1](S1, S2) {}
|
||||
|
||||
type myByte byte
|
||||
|
||||
func _(a []byte, b []myByte) {
|
||||
f00(a, b)
|
||||
f01(a, b)
|
||||
f02(a, b)
|
||||
f03(a, b)
|
||||
f04(a, b)
|
||||
f05(a, b)
|
||||
f06(a, b)
|
||||
f07(a, b)
|
||||
f08(a, b)
|
||||
f09(a, b)
|
||||
f10(a, b)
|
||||
f11(a, b)
|
||||
f12(a, b)
|
||||
f13(a, b)
|
||||
f14(a, b)
|
||||
f15(a, b)
|
||||
f16(a, b)
|
||||
f17(a, b)
|
||||
f18(a, b)
|
||||
f19(a, b)
|
||||
f20(a, b)
|
||||
f21(a, b)
|
||||
f22(a, b)
|
||||
f23(a, b)
|
||||
}
|
||||
|
||||
// Constraint type inference may have to iterate.
|
||||
// Again, the order of the type parameters shouldn't matter.
|
||||
|
||||
func g0[S ~[]E, M ~map[string]S, E any](m M) {}
|
||||
func g1[M ~map[string]S, S ~[]E, E any](m M) {}
|
||||
func g2[E any, S ~[]E, M ~map[string]S](m M) {}
|
||||
func g3[S ~[]E, E any, M ~map[string]S](m M) {}
|
||||
func g4[M ~map[string]S, E any, S ~[]E](m M) {}
|
||||
func g5[E any, M ~map[string]S, S ~[]E](m M) {}
|
||||
|
||||
func _(m map[string][]byte) {
|
||||
g0(m)
|
||||
g1(m)
|
||||
g2(m)
|
||||
g3(m)
|
||||
g4(m)
|
||||
g5(m)
|
||||
}
|
||||
|
||||
// Worst-case scenario.
|
||||
// There are 10 unknown type parameters. In each iteration of
|
||||
// constraint type inference we infer one more, from right to left.
|
||||
// Each iteration looks repeatedly at all 11 type parameters,
|
||||
// requiring a total of 10*11 = 110 iterations with the current
|
||||
// implementation. Pathological case.
|
||||
|
||||
func h[K any, J ~*K, I ~*J, H ~*I, G ~*H, F ~*G, E ~*F, D ~*E, C ~*D, B ~*C, A ~*B](x A) {}
|
||||
|
||||
func _(x **********int) {
|
||||
h(x)
|
||||
}
|
||||
|
||||
// Examples with channel constraints and tilde.
|
||||
|
||||
func ch1[P chan<- int]() (_ P) { return } // core(P) == chan<- int (single type, no tilde)
|
||||
func ch2[P ~chan int]() { return } // core(P) == ~chan<- int (tilde)
|
||||
func ch3[P chan E, E any](E) { return } // core(P) == chan<- E (single type, no tilde)
|
||||
func ch4[P chan E | ~chan<- E, E any](E) { return } // core(P) == ~chan<- E (tilde)
|
||||
func ch5[P chan int | chan<- int]() { return } // core(P) == chan<- int (not a single type)
|
||||
|
||||
func _() {
|
||||
// P can be inferred as there's a single specific type and no tilde.
|
||||
var _ chan int = ch1 /* ERROR cannot use ch1.*value of type chan<- int */ ()
|
||||
var _ chan<- int = ch1()
|
||||
|
||||
// P cannot be inferred as there's a tilde.
|
||||
ch2 /* ERROR cannot infer P */ ()
|
||||
type myChan chan int
|
||||
ch2[myChan]()
|
||||
|
||||
// P can be inferred as there's a single specific type and no tilde.
|
||||
var e int
|
||||
ch3(e)
|
||||
|
||||
// P cannot be inferred as there's more than one specific type and a tilde.
|
||||
ch4 /* ERROR cannot infer P */ (e)
|
||||
_ = ch4[chan int]
|
||||
|
||||
// P cannot be inferred as there's more than one specific type.
|
||||
ch5 /* ERROR cannot infer P */ ()
|
||||
ch5[chan<- int]()
|
||||
}
|
||||
|
||||
// test case from issue
|
||||
|
||||
func equal[M1 ~map[K1]V1, M2 ~map[K2]V2, K1, K2 ~uint32, V1, V2 ~string](m1 M1, m2 M2) bool {
|
||||
if len(m1) != len(m2) {
|
||||
return false
|
||||
}
|
||||
for k, v1 := range m1 {
|
||||
if v2, ok := m2[K2(k)]; !ok || V2(v1) != v2 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func equalFixed[K1, K2 ~uint32, V1, V2 ~string](m1 map[K1]V1, m2 map[K2]V2) bool {
|
||||
if len(m1) != len(m2) {
|
||||
return false
|
||||
}
|
||||
for k, v1 := range m1 {
|
||||
if v2, ok := m2[K2(k)]; !ok || v1 != V1(v2) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type (
|
||||
someNumericID uint32
|
||||
someStringID string
|
||||
)
|
||||
|
||||
func _() {
|
||||
foo := map[uint32]string{10: "bar"}
|
||||
bar := map[someNumericID]someStringID{10: "bar"}
|
||||
equal(foo, bar)
|
||||
}
|
||||
11
src/go/types/testdata/fixedbugs/issue51232.go2
vendored
11
src/go/types/testdata/fixedbugs/issue51232.go2
vendored
@@ -11,19 +11,20 @@ type RC[RG any] interface {
|
||||
type Fn[RCT RC[RG], RG any] func(RCT)
|
||||
|
||||
type F[RCT RC[RG], RG any] interface {
|
||||
Fn() Fn[RCT]
|
||||
Fn() Fn /* ERROR got 1 arguments */ [RCT]
|
||||
}
|
||||
|
||||
type concreteF[RCT RC[RG], RG any] struct {
|
||||
makeFn func() Fn[RCT]
|
||||
makeFn func() Fn /* ERROR got 1 arguments */ [RCT]
|
||||
}
|
||||
|
||||
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
|
||||
func (c *concreteF[RCT, RG]) Fn() Fn /* ERROR got 1 arguments */ [RCT] {
|
||||
return c.makeFn()
|
||||
}
|
||||
|
||||
func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] {
|
||||
return &concreteF[RCT]{
|
||||
func NewConcrete[RCT RC[RG], RG any](Rc RCT) F /* ERROR got 1 arguments */ [RCT] {
|
||||
// TODO(rfindley): eliminate the duplicate error below.
|
||||
return & /* ERROR cannot use .* as F\[RCT\] */ concreteF /* ERROR got 1 arguments */ [RCT]{
|
||||
makeFn: nil,
|
||||
}
|
||||
}
|
||||
|
||||
10
src/go/types/testdata/fixedbugs/issue51233.go2
vendored
10
src/go/types/testdata/fixedbugs/issue51233.go2
vendored
@@ -4,22 +4,24 @@
|
||||
|
||||
package p
|
||||
|
||||
// As of issue #51527, type-type inference has been disabled.
|
||||
|
||||
type RC[RG any] interface {
|
||||
~[]RG
|
||||
}
|
||||
|
||||
type Fn[RCT RC[RG], RG any] func(RCT)
|
||||
|
||||
type FFn[RCT RC[RG], RG any] func() Fn[RCT]
|
||||
type FFn[RCT RC[RG], RG any] func() Fn /* ERROR got 1 arguments */ [RCT]
|
||||
|
||||
type F[RCT RC[RG], RG any] interface {
|
||||
Fn() Fn[RCT]
|
||||
Fn() Fn /* ERROR got 1 arguments */ [RCT]
|
||||
}
|
||||
|
||||
type concreteF[RCT RC[RG], RG any] struct {
|
||||
makeFn FFn[RCT]
|
||||
makeFn FFn /* ERROR got 1 arguments */ [RCT]
|
||||
}
|
||||
|
||||
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] {
|
||||
func (c *concreteF[RCT, RG]) Fn() Fn /* ERROR got 1 arguments */ [RCT] {
|
||||
return c.makeFn()
|
||||
}
|
||||
|
||||
@@ -10,7 +10,9 @@ package p
|
||||
type T[P any, B *P] struct{}
|
||||
|
||||
func (T /* ERROR cannot use generic type */ ) m0() {}
|
||||
func (/* ERROR got 1 type parameter, but receiver base type declares 2 */ T[_]) m1() {}
|
||||
|
||||
// TODO(rfindley): eliminate the duplicate errors here.
|
||||
func (/* ERROR got 1 type parameter, but receiver base type declares 2 */ T /* ERROR got 1 arguments but 2 type parameters */ [_]) m1() {}
|
||||
func (T[_, _]) m2() {}
|
||||
// TODO(gri) this error is unfortunate (issue #51343)
|
||||
func (T /* ERROR got 3 arguments but 2 type parameters */ [_, _, _]) m3() {}
|
||||
|
||||
24
src/go/types/testdata/fixedbugs/issue51376.go2
vendored
Normal file
24
src/go/types/testdata/fixedbugs/issue51376.go2
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2022 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
|
||||
|
||||
type Map map[string]int
|
||||
|
||||
func f[M ~map[K]V, K comparable, V any](M) {}
|
||||
func g[M map[K]V, K comparable, V any](M) {}
|
||||
|
||||
func _[M1 ~map[K]V, M2 map[K]V, K comparable, V any]() {
|
||||
var m1 M1
|
||||
f(m1)
|
||||
g /* ERROR M1 does not implement map\[K\]V */ (m1) // M1 has tilde
|
||||
|
||||
var m2 M2
|
||||
f(m2)
|
||||
g(m2) // M1 does not have tilde
|
||||
|
||||
var m3 Map
|
||||
f(m3)
|
||||
g /* ERROR Map does not implement map\[string\]int */ (m3) // M in g does not have tilde
|
||||
}
|
||||
17
src/go/types/testdata/fixedbugs/issue51437.go
vendored
Normal file
17
src/go/types/testdata/fixedbugs/issue51437.go
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2022 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
|
||||
|
||||
type T struct{}
|
||||
|
||||
func (T) m() []int { return nil }
|
||||
|
||||
func f(x T) {
|
||||
for _, x := range func() []int {
|
||||
return x.m() // x declared in parameter list of f
|
||||
}() {
|
||||
_ = x // x declared by range clause
|
||||
}
|
||||
}
|
||||
54
src/go/types/testdata/fixedbugs/issue51472.go2
vendored
Normal file
54
src/go/types/testdata/fixedbugs/issue51472.go2
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright 2022 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 _[T comparable](x T) {
|
||||
_ = x == x
|
||||
}
|
||||
|
||||
func _[T interface{interface{comparable}}](x T) {
|
||||
_ = x == x
|
||||
}
|
||||
|
||||
func _[T interface{comparable; interface{comparable}}](x T) {
|
||||
_ = x == x
|
||||
}
|
||||
|
||||
func _[T interface{comparable; ~int}](x T) {
|
||||
_ = x == x
|
||||
}
|
||||
|
||||
func _[T interface{comparable; ~[]byte}](x T) {
|
||||
_ = x /* ERROR cannot compare */ == x
|
||||
}
|
||||
|
||||
// TODO(gri) The error message here should be better. See issue #51525.
|
||||
func _[T interface{comparable; ~int; ~string}](x T) {
|
||||
_ = x /* ERROR cannot compare */ == x
|
||||
}
|
||||
|
||||
// TODO(gri) The error message here should be better. See issue #51525.
|
||||
func _[T interface{~int; ~string}](x T) {
|
||||
_ = x /* ERROR cannot compare */ == x
|
||||
}
|
||||
|
||||
func _[T interface{comparable; interface{~int}; interface{int|float64}}](x T) {
|
||||
_ = x == x
|
||||
}
|
||||
|
||||
func _[T interface{interface{comparable; ~int}; interface{~float64; comparable; m()}}](x T) {
|
||||
_ = x /* ERROR cannot compare */ == x
|
||||
}
|
||||
|
||||
// test case from issue
|
||||
|
||||
func f[T interface{comparable; []byte|string}](x T) {
|
||||
_ = x == x
|
||||
}
|
||||
|
||||
func _(s []byte) {
|
||||
f /* ERROR \[\]byte does not implement interface{comparable; \[\]byte\|string} */ (s)
|
||||
_ = f[[ /* ERROR does not implement */ ]byte]
|
||||
}
|
||||
7
src/go/types/testdata/fixedbugs/issue51509.go
vendored
Normal file
7
src/go/types/testdata/fixedbugs/issue51509.go
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
// Copyright 2022 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
|
||||
|
||||
type T /* ERROR illegal cycle */ T.x
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user