mirror of
https://github.com/golang/go.git
synced 2026-01-29 07:02:05 +03:00
Compare commits
35 Commits
3604782621
...
go1.21.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c19c4c566c | ||
|
|
e973d24261 | ||
|
|
2e6276df34 | ||
|
|
aeef93cd64 | ||
|
|
35de5f2b0e | ||
|
|
a3b092d65e | ||
|
|
07c72a0915 | ||
|
|
041dd5ce05 | ||
|
|
a51957fb0b | ||
|
|
363f2594aa | ||
|
|
9b53b9b585 | ||
|
|
4a14d9c9af | ||
|
|
9786164333 | ||
|
|
6df6e61cbb | ||
|
|
b25266c58d | ||
|
|
1ea8d38517 | ||
|
|
b2ffc23a82 | ||
|
|
8472fcb62d | ||
|
|
b36e5555dd | ||
|
|
ed977e2f47 | ||
|
|
2fabb143d7 | ||
|
|
c9f01f0ec7 | ||
|
|
252f20b2c1 | ||
|
|
7ee7a21ef2 | ||
|
|
06a9034b60 | ||
|
|
03c7e96be9 | ||
|
|
c2de6836c1 | ||
|
|
4aeac326b5 | ||
|
|
9480b4adf9 | ||
|
|
cc0cb3020d | ||
|
|
d8117459c5 | ||
|
|
ebbff91f59 | ||
|
|
1c1c82432a | ||
|
|
b4a0665266 | ||
|
|
577e7b9bb9 |
@@ -60,7 +60,9 @@ pkg crypto/tls, method (*QUICConn) Close() error #44886
|
||||
pkg crypto/tls, method (*QUICConn) ConnectionState() ConnectionState #44886
|
||||
pkg crypto/tls, method (*QUICConn) HandleData(QUICEncryptionLevel, []uint8) error #44886
|
||||
pkg crypto/tls, method (*QUICConn) NextEvent() QUICEvent #44886
|
||||
pkg crypto/tls, method (*QUICConn) SendSessionTicket(bool) error #60107
|
||||
pkg crypto/tls, method (*QUICConn) SendSessionTicket(QUICSessionTicketOptions) error #60107
|
||||
pkg crypto/tls, type QUICSessionTicketOptions struct #60107
|
||||
pkg crypto/tls, type QUICSessionTicketOptions struct, EarlyData bool #60107
|
||||
pkg crypto/tls, method (*QUICConn) SetTransportParameters([]uint8) #44886
|
||||
pkg crypto/tls, method (*QUICConn) Start(context.Context) error #44886
|
||||
pkg crypto/tls, method (QUICEncryptionLevel) String() string #44886
|
||||
@@ -344,8 +346,6 @@ pkg maps, func Copy[$0 interface{ ~map[$2]$3 }, $1 interface{ ~map[$2]$3 }, $2 c
|
||||
pkg maps, func DeleteFunc[$0 interface{ ~map[$1]$2 }, $1 comparable, $2 interface{}]($0, func($1, $2) bool) #57436
|
||||
pkg maps, func Equal[$0 interface{ ~map[$2]$3 }, $1 interface{ ~map[$2]$3 }, $2 comparable, $3 comparable]($0, $1) bool #57436
|
||||
pkg maps, func EqualFunc[$0 interface{ ~map[$2]$3 }, $1 interface{ ~map[$2]$4 }, $2 comparable, $3 interface{}, $4 interface{}]($0, $1, func($3, $4) bool) bool #57436
|
||||
pkg maps, func Keys[$0 interface{ ~map[$1]$2 }, $1 comparable, $2 interface{}]($0) []$1 #57436
|
||||
pkg maps, func Values[$0 interface{ ~map[$1]$2 }, $1 comparable, $2 interface{}]($0) []$2 #57436
|
||||
pkg math/big, method (*Int) Float64() (float64, Accuracy) #56984
|
||||
pkg net/http, method (*ProtocolError) Is(error) bool #41198
|
||||
pkg net/http, method (*ResponseController) EnableFullDuplex() error #57786
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
branch: master
|
||||
branch: release-branch.go1.21
|
||||
parent-branch: master
|
||||
|
||||
1264
doc/go1.21.html
1264
doc/go1.21.html
File diff suppressed because it is too large
Load Diff
756
doc/go_spec.html
756
doc/go_spec.html
@@ -1,6 +1,6 @@
|
||||
<!--{
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Version of June 14, 2023",
|
||||
"Subtitle": "Version of Aug 2, 2023",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
@@ -2511,7 +2511,7 @@ type (
|
||||
|
||||
<p>
|
||||
A type definition creates a new, distinct type with the same
|
||||
<a href="#Types">underlying type</a> and operations as the given type
|
||||
<a href="#Underlying_types">underlying type</a> and operations as the given type
|
||||
and binds an identifier, the <i>type name</i>, to it.
|
||||
</p>
|
||||
|
||||
@@ -4343,7 +4343,7 @@ type parameter list type arguments after substitution
|
||||
When using a generic function, type arguments may be provided explicitly,
|
||||
or they may be partially or completely <a href="#Type_inference">inferred</a>
|
||||
from the context in which the function is used.
|
||||
Provided that they can be inferred, type arguments may be omitted entirely if the function is:
|
||||
Provided that they can be inferred, type argument lists may be omitted entirely if the function is:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
@@ -4351,7 +4351,7 @@ Provided that they can be inferred, type arguments may be omitted entirely if th
|
||||
<a href="#Calls">called</a> with ordinary arguments,
|
||||
</li>
|
||||
<li>
|
||||
<a href="#Assignment_statements">assigned</a> to a variable with an explicitly declared type,
|
||||
<a href="#Assignment_statements">assigned</a> to a variable with a known type
|
||||
</li>
|
||||
<li>
|
||||
<a href="#Calls">passed as an argument</a> to another function, or
|
||||
@@ -4371,7 +4371,7 @@ must be inferrable from the context in which the function is used.
|
||||
// sum returns the sum (concatenation, for strings) of its arguments.
|
||||
func sum[T ~int | ~float64 | ~string](x... T) T { … }
|
||||
|
||||
x := sum // illegal: sum must have a type argument (x is a variable without a declared type)
|
||||
x := sum // illegal: the type of x is unknown
|
||||
intSum := sum[int] // intSum has type func(x... int) int
|
||||
a := intSum(2, 3) // a has value 5 of type int
|
||||
b := sum[float64](2.0, 3) // b has value 5.0 of type float64
|
||||
@@ -4406,402 +4406,323 @@ For a generic type, all type arguments must always be provided explicitly.
|
||||
<h3 id="Type_inference">Type inference</h3>
|
||||
|
||||
<p>
|
||||
<em>NOTE: This section is not yet up-to-date for Go 1.21.</em>
|
||||
A use of a generic function may omit some or all type arguments if they can be
|
||||
<i>inferred</i> from the context within which the function is used, including
|
||||
the constraints of the function's type parameters.
|
||||
Type inference succeeds if it can infer the missing type arguments
|
||||
and <a href="#Instantiations">instantiation</a> succeeds with the
|
||||
inferred type arguments.
|
||||
Otherwise, type inference fails and the program is invalid.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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
|
||||
for type parameters and verify that each type argument
|
||||
<a href="#Implementing_an_interface">implements</a> the relevant constraint;
|
||||
it is possible for an inferred type argument to fail to implement a constraint, in which
|
||||
case instantiation fails.
|
||||
Type inference uses the type relationships between pairs of types for inference:
|
||||
For instance, a function argument must be <a href="#Assignability">assignable</a>
|
||||
to its respective function parameter; this establishes a relationship between the
|
||||
type of the argument and the type of the parameter.
|
||||
If either of these two types contains type parameters, type inference looks for the
|
||||
type arguments to substitute the type parameters with such that the assignability
|
||||
relationship is satisfied.
|
||||
Similarly, type inference uses the fact that a type argument must
|
||||
<a href="#Satisfying_a_type_constraint">satisfy</a> the constraint of its respective
|
||||
type parameter.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Type inference is based on
|
||||
Each such pair of matched types corresponds to a <i>type equation</i> containing
|
||||
one or multiple type parameters, from one or possibly multiple generic functions.
|
||||
Inferring the missing type arguments means solving the resulting set of type
|
||||
equations for the respective type parameters.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For example, given
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
// dedup returns a copy of the argument slice with any duplicate entries removed.
|
||||
func dedup[S ~[]E, E comparable](S) S { … }
|
||||
|
||||
type Slice []int
|
||||
var s Slice
|
||||
s = dedup(s) // same as s = dedup[Slice, int](s)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
the variable <code>s</code> of type <code>Slice</code> must be assignable to
|
||||
the function parameter type <code>S</code> for the program to be valid.
|
||||
To reduce complexity, type inference ignores the directionality of assignments,
|
||||
so the type relationship between <code>Slice</code> and <code>S</code> can be
|
||||
expressed via the (symmetric) type equation <code>Slice ≡<sub>A</sub> S</code>
|
||||
(or <code>S ≡<sub>A</sub> Slice</code> for that matter),
|
||||
where the <code><sub>A</sub></code> in <code>≡<sub>A</sub></code>
|
||||
indicates that the LHS and RHS types must match per assignability rules
|
||||
(see the section on <a href="#Type_unification">type unification</a> for
|
||||
details).
|
||||
Similarly, the type parameter <code>S</code> must satisfy its constraint
|
||||
<code>~[]E</code>. This can be expressed as <code>S ≡<sub>C</sub> ~[]E</code>
|
||||
where <code>X ≡<sub>C</sub> Y</code> stands for
|
||||
"<code>X</code> satisfies constraint <code>Y</code>".
|
||||
These observations lead to a set of two equations
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
Slice ≡<sub>A</sub> S (1)
|
||||
S ≡<sub>C</sub> ~[]E (2)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
which now can be solved for the type parameters <code>S</code> and <code>E</code>.
|
||||
From (1) a compiler can infer that the type argument for <code>S</code> is <code>Slice</code>.
|
||||
Similarly, because the underlying type of <code>Slice</code> is <code>[]int</code>
|
||||
and <code>[]int</code> must match <code>[]E</code> of the constraint,
|
||||
a compiler can infer that <code>E</code> must be <code>int</code>.
|
||||
Thus, for these two equations, type inference infers
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
S ➞ Slice
|
||||
E ➞ int
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Given a set of type equations, the type parameters to solve for are
|
||||
the type parameters of the functions that need to be instantiated
|
||||
and for which no explicit type arguments is provided.
|
||||
These type parameters are called <i>bound</i> type parameters.
|
||||
For instance, in the <code>dedup</code> example above, the type parameters
|
||||
<code>P</code> and <code>E</code> are bound to <code>dedup</code>.
|
||||
An argument to a generic function call may be a generic function itself.
|
||||
The type parameters of that function are included in the set of bound
|
||||
type parameters.
|
||||
The types of function arguments may contain type parameters from other
|
||||
functions (such as a generic function enclosing a function call).
|
||||
Those type parameters may also appear in type equations but they are
|
||||
not bound in that context.
|
||||
Type equations are always solved for the bound type parameters only.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Type inference supports calls of generic functions and assignments
|
||||
of generic functions to (explicitly function-typed) variables.
|
||||
This includes passing generic functions as arguments to other
|
||||
(possibly also generic) functions, and returning generic functions
|
||||
as results.
|
||||
Type inference operates on a set of equations specific to each of
|
||||
these cases.
|
||||
The equations are as follows (type argument lists are omitted for clarity):
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
a <a href="#Type_parameter_declarations">type parameter list</a>
|
||||
<p>
|
||||
For a function call <code>f(a<sub>0</sub>, a<sub>1</sub>, …)</code> where
|
||||
<code>f</code> or a function argument <code>a<sub>i</sub></code> is
|
||||
a generic function:
|
||||
<br>
|
||||
Each pair <code>(a<sub>i</sub>, p<sub>i</sub>)</code> of corresponding
|
||||
function arguments and parameters where <code>a<sub>i</sub></code> is not an
|
||||
<a href="#Constants">untyped constant</a> yields an equation
|
||||
<code>typeof(p<sub>i</sub>) ≡<sub>A</sub> typeof(a<sub>i</sub>)</code>.
|
||||
<br>
|
||||
If <code>a<sub>i</sub></code> is an untyped constant <code>c<sub>j</sub></code>,
|
||||
and <code>typeof(p<sub>i</sub>)</code> is a bound type parameter <code>P<sub>k</sub></code>,
|
||||
the pair <code>(c<sub>j</sub>, P<sub>k</sub>)</code> is collected separately from
|
||||
the type equations.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
a substitution map <i>M</i> initialized with the known type arguments, if any
|
||||
<p>
|
||||
For an assignment <code>v = f</code> of a generic function <code>f</code> to a
|
||||
(non-generic) variable <code>v</code> of function type:
|
||||
<br>
|
||||
<code>typeof(v) ≡<sub>A</sub> typeof(f)</code>.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
a (possibly empty) list of ordinary function arguments (in case of a function call only)
|
||||
<p>
|
||||
For a return statement <code>return …, f, … </code> where <code>f</code> is a
|
||||
generic function returned as a result to a (non-generic) result variable
|
||||
<code>r</code> of function type:
|
||||
<br>
|
||||
<code>typeof(r) ≡<sub>A</sub> typeof(f)</code>.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
and then proceeds with the following steps:
|
||||
Additionally, each type parameter <code>P<sub>k</sub></code> and corresponding type constraint
|
||||
<code>C<sub>k</sub></code> yields the type equation
|
||||
<code>P<sub>k</sub> ≡<sub>C</sub> C<sub>k</sub></code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Type inference gives precedence to type information obtained from typed operands
|
||||
before considering untyped constants.
|
||||
Therefore, inference proceeds in two phases:
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
<li>
|
||||
apply <a href="#Function_argument_type_inference"><i>function argument type inference</i></a>
|
||||
to all <i>typed</i> ordinary function arguments
|
||||
<p>
|
||||
The type equations are solved for the bound
|
||||
type parameters using <a href="#Type_unification">type unification</a>.
|
||||
If unification fails, type inference fails.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
apply <a href="#Constraint_type_inference"><i>constraint type inference</i></a>
|
||||
</li>
|
||||
<li>
|
||||
apply function argument type inference to all <i>untyped</i> ordinary function arguments
|
||||
using the default type for each of the untyped function arguments
|
||||
</li>
|
||||
<li>
|
||||
apply constraint type inference
|
||||
<p>
|
||||
For each bound type parameter <code>P<sub>k</sub></code> for which no type argument
|
||||
has been inferred yet and for which one or more pairs
|
||||
<code>(c<sub>j</sub>, P<sub>k</sub>)</code> with that same type parameter
|
||||
were collected, determine the <a href="#Constant_expressions">constant kind</a>
|
||||
of the constants <code>c<sub>j</sub></code> in all those pairs the same way as for
|
||||
<a href="#Constant_expressions">constant expressions</a>.
|
||||
The type argument for <code>P<sub>k</sub></code> is the
|
||||
<a href="#Constants">default type</a> for the determined constant kind.
|
||||
If a constant kind cannot be determined due to conflicting constant kinds,
|
||||
type inference fails.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
If there are no ordinary or untyped function arguments, the respective steps are skipped.
|
||||
Constraint type inference is skipped if the previous step didn't infer any new type arguments,
|
||||
but it is run at least once if there are missing type arguments.
|
||||
If not all type arguments have been found after these two phases, type inference fails.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The substitution map <i>M</i> is carried through all steps, and each step may add entries to <i>M</i>.
|
||||
The process stops as soon as <i>M</i> has a type argument for each type parameter or if an inference step fails.
|
||||
If an inference step fails, or if <i>M</i> is still missing type arguments after the last step, type inference fails.
|
||||
If the two phases are successful, type inference determined a type argument for each
|
||||
bound type parameter:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
P<sub>k</sub> ➞ A<sub>k</sub>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
A type argument <code>A<sub>k</sub></code> may be a composite type,
|
||||
containing other bound type parameters <code>P<sub>k</sub></code> as element types
|
||||
(or even be just another bound type parameter).
|
||||
In a process of repeated simplification, the bound type parameters in each type
|
||||
argument are substituted with the respective type arguments for those type
|
||||
parameters until each type argument is free of bound type parameters.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If type arguments contain cyclic references to themselves
|
||||
through bound type parameters, simplification and thus type
|
||||
inference fails.
|
||||
Otherwise, type inference succeeds.
|
||||
</p>
|
||||
|
||||
<h4 id="Type_unification">Type unification</h4>
|
||||
|
||||
<p>
|
||||
Type inference is based on <i>type unification</i>. A single unification step
|
||||
applies to a <a href="#Type_inference">substitution map</a> and two types, either
|
||||
or both of which may be or contain type parameters. The substitution map tracks
|
||||
the known (explicitly provided or already inferred) type arguments: the map
|
||||
contains an entry <code>P</code> → <code>A</code> for each type
|
||||
parameter <code>P</code> and corresponding known type argument <code>A</code>.
|
||||
During unification, known type arguments take the place of their corresponding type
|
||||
parameters when comparing types. Unification is the process of finding substitution
|
||||
map entries that make the two types equivalent.
|
||||
Type inference solves type equations through <i>type unification</i>.
|
||||
Type unification recursively compares the LHS and RHS types of an
|
||||
equation, where either or both types may be or contain bound type parameters,
|
||||
and looks for type arguments for those type parameters such that the LHS
|
||||
and RHS match (become identical or assignment-compatible, depending on
|
||||
context).
|
||||
To that effect, type inference maintains a map of bound type parameters
|
||||
to inferred type arguments; this map is consulted and updated during type unification.
|
||||
Initially, the bound type parameters are known but the map is empty.
|
||||
During type unification, if a new type argument <code>A</code> is inferred,
|
||||
the respective mapping <code>P ➞ A</code> from type parameter to argument
|
||||
is added to the map.
|
||||
Conversely, when comparing types, a known type argument
|
||||
(a type argument for which a map entry already exists)
|
||||
takes the place of its corresponding type parameter.
|
||||
As type inference progresses, the map is populated more and more
|
||||
until all equations have been considered, or until unification fails.
|
||||
Type inference succeeds if no unification step fails and the map has
|
||||
an entry for each type parameter.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For unification, two types that don't contain any type parameters from the current type
|
||||
parameter list are <i>equivalent</i>
|
||||
if they are identical, or if they are channel types that are identical ignoring channel
|
||||
direction, or if their underlying types are equivalent.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Unification works by comparing the structure of pairs of types: their structure
|
||||
disregarding type parameters must be identical, and types other than type parameters
|
||||
must be equivalent.
|
||||
A type parameter in one type may match any complete subtype in the other type;
|
||||
each successful match causes an entry to be added to the substitution map.
|
||||
If the structure differs, or types other than type parameters are not equivalent,
|
||||
unification fails.
|
||||
</p>
|
||||
|
||||
<!--
|
||||
TODO(gri) Somewhere we need to describe the process of adding an entry to the
|
||||
substitution map: if the entry is already present, the type argument
|
||||
values are themselves unified.
|
||||
-->
|
||||
|
||||
<p>
|
||||
For example, if <code>T1</code> and <code>T2</code> are type parameters,
|
||||
<code>[]map[int]bool</code> can be unified with any of the following:
|
||||
</pre>
|
||||
For example, given the type equation with the bound type parameter
|
||||
<code>P</code>
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
[]map[int]bool // types are identical
|
||||
T1 // adds T1 → []map[int]bool to substitution map
|
||||
[]T1 // adds T1 → map[int]bool to substitution map
|
||||
[]map[T1]T2 // adds T1 → int and T2 → bool to substitution map
|
||||
[10]struct{ elem P, list []P } ≡<sub>A</sub> [10]struct{ elem string; list []string }
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
On the other hand, <code>[]map[int]bool</code> cannot be unified with any of
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
int // int is not a slice
|
||||
struct{} // a struct is not a slice
|
||||
[]struct{} // a struct is not a map
|
||||
[]map[T1]string // map element types don't match
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
As an exception to this general rule, because a <a href="#Type_definitions">defined type</a>
|
||||
<code>D</code> and a type literal <code>L</code> are never equivalent,
|
||||
unification compares the underlying type of <code>D</code> with <code>L</code> instead.
|
||||
For example, given the defined type
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type Vector []float64
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
and the type literal <code>[]E</code>, unification compares <code>[]float64</code> with
|
||||
<code>[]E</code> and adds an entry <code>E</code> → <code>float64</code> to
|
||||
the substitution map.
|
||||
</p>
|
||||
|
||||
<h4 id="Function_argument_type_inference">Function argument type inference</h4>
|
||||
|
||||
<!-- In this section and the section on constraint type inference we start with examples
|
||||
rather than have the examples follow the rules as is customary elsewhere in spec.
|
||||
Hopefully this helps building an intuition and makes the rules easier to follow. -->
|
||||
|
||||
<p>
|
||||
Function argument type inference infers type arguments from function arguments:
|
||||
if a function parameter is declared with a type <code>T</code> that uses
|
||||
type parameters,
|
||||
<a href="#Type_unification">unifying</a> the type of the corresponding
|
||||
function argument with <code>T</code> may infer type arguments for the type
|
||||
parameters used by <code>T</code>.
|
||||
type inference starts with an empty map.
|
||||
Unification first compares the top-level structure of the LHS and RHS
|
||||
types.
|
||||
Both are arrays of the same length; they unify if the element types unify.
|
||||
Both element types are structs; they unify if they have
|
||||
the same number of fields with the same names and if the
|
||||
field types unify.
|
||||
The type argument for <code>P</code> is not known yet (there is no map entry),
|
||||
so unifying <code>P</code> with <code>string</code> adds
|
||||
the mapping <code>P ➞ string</code> to the map.
|
||||
Unifying the types of the <code>list</code> field requires
|
||||
unifying <code>[]P</code> and <code>[]string</code> and
|
||||
thus <code>P</code> and <code>string</code>.
|
||||
Since the type argument for <code>P</code> is known at this point
|
||||
(there is a map entry for <code>P</code>), its type argument
|
||||
<code>string</code> takes the place of <code>P</code>.
|
||||
And since <code>string</code> is identical to <code>string</code>,
|
||||
this unification step succeeds as well.
|
||||
Unification of the LHS and RHS of the equation is now finished.
|
||||
Type inference succeeds because there is only one type equation,
|
||||
no unification step failed, and the map is fully populated.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For instance, given the generic function
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func scale[Number ~int64|~float64|~complex128](v []Number, s Number) []Number
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
and the call
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var vector []float64
|
||||
scaledVector := scale(vector, 42)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
the type argument for <code>Number</code> can be inferred from the function argument
|
||||
<code>vector</code> by unifying the type of <code>vector</code> with the corresponding
|
||||
parameter type: <code>[]float64</code> and <code>[]Number</code>
|
||||
match in structure and <code>float64</code> matches with <code>Number</code>.
|
||||
This adds the entry <code>Number</code> → <code>float64</code> to the
|
||||
<a href="#Type_unification">substitution map</a>.
|
||||
Untyped arguments, such as the second function argument <code>42</code> here, are ignored
|
||||
in the first round of function argument type inference and only considered if there are
|
||||
unresolved type parameters left.
|
||||
Unification uses a combination of <i>exact</i> and <i>loose</i>
|
||||
unification depending on whether two types have to be
|
||||
<a href="#Type_identity">identical</a>,
|
||||
<a href="#Assignability">assignment-compatible</a>, or
|
||||
only structurally equal.
|
||||
The respective <a href="#Type_unification_rules">type unification rules</a>
|
||||
are spelled out in detail in the <a href="#Appendix">Appendix</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Inference happens in two separate phases; each phase operates on a specific list of
|
||||
(parameter, argument) pairs:
|
||||
For an equation of the form <code>X ≡<sub>A</sub> Y</code>,
|
||||
where <code>X</code> and <code>Y</code> are types involved
|
||||
in an assignment (including parameter passing and return statements),
|
||||
the top-level type structures may unify loosely but element types
|
||||
must unify exactly, matching the rules for assignments.
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
<p>
|
||||
For an equation of the form <code>P ≡<sub>C</sub> C</code>,
|
||||
where <code>P</code> is a type parameter and <code>C</code>
|
||||
its corresponding constraint, the unification rules are bit
|
||||
more complicated:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
The list <i>Lt</i> contains all (parameter, argument) pairs where the parameter
|
||||
type uses type parameters and where the function argument is <i>typed</i>.
|
||||
If <code>C</code> has a <a href="#Core_types">core type</a>
|
||||
<code>core(C)</code>
|
||||
and <code>P</code> has a known type argument <code>A</code>,
|
||||
<code>core(C)</code> and <code>A</code> must unify loosely.
|
||||
If <code>P</code> does not have a known type argument
|
||||
and <code>C</code> contains exactly one type term <code>T</code>
|
||||
that is not an underlying (tilde) type, unification adds the
|
||||
mapping <code>P ➞ T</code> to the map.
|
||||
</li>
|
||||
<li>
|
||||
The list <i>Lu</i> contains all remaining pairs where the parameter type is a single
|
||||
type parameter. In this list, the respective function arguments are untyped.
|
||||
If <code>C</code> does not have a core type
|
||||
and <code>P</code> has a known type argument <code>A</code>,
|
||||
<code>A</code> must have all methods of <code>C</code>, if any,
|
||||
and corresponding method types must unify exactly.
|
||||
</li>
|
||||
</ol>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Any other (parameter, argument) pair is ignored.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
By construction, the arguments of the pairs in <i>Lu</i> are <i>untyped</i> constants
|
||||
(or the untyped boolean result of a comparison). And because <a href="#Constants">default types</a>
|
||||
of untyped values are always predeclared non-composite types, they can never match against
|
||||
a composite type, so it is sufficient to only consider parameter types that are single type
|
||||
parameters.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Each list is processed in a separate phase:
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
<li>
|
||||
In the first phase, the parameter and argument types of each pair in <i>Lt</i>
|
||||
are unified. If unification succeeds for a pair, it may yield new entries that
|
||||
are added to the substitution map <i>M</i>. If unification fails, type inference
|
||||
fails.
|
||||
</li>
|
||||
<li>
|
||||
The second phase considers the entries of list <i>Lu</i>. Type parameters for
|
||||
which the type argument has already been determined are ignored in this phase.
|
||||
For each remaining pair, the parameter type (which is a single type parameter) and
|
||||
the <a href="#Constants">default type</a> of the corresponding untyped argument is
|
||||
unified. If unification fails, type inference fails.
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
While unification is successful, processing of each list continues until all list elements
|
||||
are considered, even if all type arguments are inferred before the last list element has
|
||||
been processed.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Example:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
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
|
||||
min(1.0, 2.0) // T is float64, inferred from default type for 1.0 and matches default type for 2.0
|
||||
min(1.0, 2) // illegal: default type float64 (for 1.0) doesn't match default type int (for 2)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
In the example <code>min(1.0, 2)</code>, processing the function argument <code>1.0</code>
|
||||
yields the substitution map entry <code>T</code> → <code>float64</code>. Because
|
||||
processing continues until all untyped arguments are considered, an error is reported. This
|
||||
ensures that type inference does not depend on the order of the untyped arguments.
|
||||
</p>
|
||||
|
||||
<h4 id="Constraint_type_inference">Constraint type inference</h4>
|
||||
|
||||
<p>
|
||||
Constraint type inference infers type arguments by considering type constraints.
|
||||
If a type parameter <code>P</code> has a constraint with a
|
||||
<a href="#Core_types">core type</a> <code>C</code>,
|
||||
<a href="#Type_unification">unifying</a> <code>P</code> with <code>C</code>
|
||||
may infer additional type arguments, either the type argument for <code>P</code>,
|
||||
or if that is already known, possibly the type arguments for type parameters
|
||||
used in <code>C</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For instance, consider the type parameter list with type parameters <code>List</code> and
|
||||
<code>Elem</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
[List ~[]Elem, Elem any]
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Constraint type inference can deduce the type of <code>Elem</code> from the type argument
|
||||
for <code>List</code> because <code>Elem</code> is a type parameter in the core type
|
||||
<code>[]Elem</code> of <code>List</code>.
|
||||
If the type argument is <code>Bytes</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type Bytes []byte
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
unifying the underlying type of <code>Bytes</code> with the core type means
|
||||
unifying <code>[]byte</code> with <code>[]Elem</code>. That unification succeeds and yields
|
||||
the <a href="#Type_unification">substitution map</a> entry
|
||||
<code>Elem</code> → <code>byte</code>.
|
||||
Thus, in this example, constraint type inference can infer the second type argument from the
|
||||
first one.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Using the core type of a constraint may lose some information: In the (unlikely) case that
|
||||
the constraint's type set contains a single <a href="#Type_definitions">defined type</a>
|
||||
<code>N</code>, the corresponding core type is <code>N</code>'s underlying type rather than
|
||||
<code>N</code> itself. In this case, constraint type inference may succeed but instantiation
|
||||
will fail because the inferred type is not in the type set of the constraint.
|
||||
Thus, constraint type inference uses the <i>adjusted core type</i> of
|
||||
a constraint: if the type set contains a single type, use that type; otherwise use the
|
||||
constraint's core type.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Generally, constraint type inference proceeds in two phases: Starting with a given
|
||||
substitution map <i>M</i>
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
<li>
|
||||
For all type parameters with an adjusted core type, unify the type parameter with that
|
||||
type. If any unification fails, constraint type inference fails.
|
||||
</li>
|
||||
|
||||
<li>
|
||||
At this point, some entries in <i>M</i> may map type parameters to other
|
||||
type parameters or to types containing type parameters. For each entry
|
||||
<code>P</code> → <code>A</code> in <i>M</i> where <code>A</code> is or
|
||||
contains type parameters <code>Q</code> for which there exist entries
|
||||
<code>Q</code> → <code>B</code> in <i>M</i>, substitute those
|
||||
<code>Q</code> with the respective <code>B</code> in <code>A</code>.
|
||||
Stop when no further substitution is possible.
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
The result of constraint type inference is the final substitution map <i>M</i> from type
|
||||
parameters <code>P</code> to type arguments <code>A</code> where no type parameter <code>P</code>
|
||||
appears in any of the <code>A</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For instance, given the type parameter list
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
[A any, B []C, C *A]
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
and the single provided type argument <code>int</code> for type parameter <code>A</code>,
|
||||
the initial substitution map <i>M</i> contains the entry <code>A</code> → <code>int</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In the first phase, the type parameters <code>B</code> and <code>C</code> are unified
|
||||
with the core type of their respective constraints. This adds the entries
|
||||
<code>B</code> → <code>[]C</code> and <code>C</code> → <code>*A</code>
|
||||
to <i>M</i>.
|
||||
|
||||
<p>
|
||||
At this point there are two entries in <i>M</i> where the right-hand side
|
||||
is or contains type parameters for which there exists other entries in <i>M</i>:
|
||||
<code>[]C</code> and <code>*A</code>.
|
||||
In the second phase, these type parameters are replaced with their respective
|
||||
types. It doesn't matter in which order this happens. Starting with the state
|
||||
of <i>M</i> after the first phase:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<code>A</code> → <code>int</code>,
|
||||
<code>B</code> → <code>[]C</code>,
|
||||
<code>C</code> → <code>*A</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Replace <code>A</code> on the right-hand side of → with <code>int</code>:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<code>A</code> → <code>int</code>,
|
||||
<code>B</code> → <code>[]C</code>,
|
||||
<code>C</code> → <code>*int</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Replace <code>C</code> on the right-hand side of → with <code>*int</code>:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<code>A</code> → <code>int</code>,
|
||||
<code>B</code> → <code>[]*int</code>,
|
||||
<code>C</code> → <code>*int</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
At this point no further substitution is possible and the map is full.
|
||||
Therefore, <code>M</code> represents the final map of type parameters
|
||||
to type arguments for the given type parameter list.
|
||||
When solving type equations from type constraints,
|
||||
solving one equation may infer additional type arguments,
|
||||
which in turn may enable solving other equations that depend
|
||||
on those type arguments.
|
||||
Type inference repeats type unification as long as new type
|
||||
arguments are inferred.
|
||||
</p>
|
||||
|
||||
<h3 id="Operators">Operators</h3>
|
||||
@@ -5479,7 +5400,7 @@ in any of these cases:
|
||||
ignoring struct tags (see below),
|
||||
<code>x</code>'s type and <code>T</code> are not
|
||||
<a href="#Type_parameter_declarations">type parameters</a> but have
|
||||
<a href="#Type_identity">identical</a> <a href="#Types">underlying types</a>.
|
||||
<a href="#Type_identity">identical</a> <a href="#Underlying_types">underlying types</a>.
|
||||
</li>
|
||||
<li>
|
||||
ignoring struct tags (see below),
|
||||
@@ -7324,7 +7245,8 @@ clear(t) type parameter see below
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If the argument type is a <a href="#Type_parameter_declarations">type parameter</a>,
|
||||
If the type of the argument to <code>clear</code> is a
|
||||
<a href="#Type_parameter_declarations">type parameter</a>,
|
||||
all types in its type set must be maps or slices, and <code>clear</code>
|
||||
performs the operation corresponding to the actual type argument.
|
||||
</p>
|
||||
@@ -8290,7 +8212,7 @@ 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
|
||||
Any pointer or value of <a href="#Underlying_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>
|
||||
@@ -8438,3 +8360,145 @@ The following minimal alignment properties are guaranteed:
|
||||
<p>
|
||||
A struct or array type has size zero if it contains no fields (or elements, respectively) that have a size greater than zero. Two distinct zero-size variables may have the same address in memory.
|
||||
</p>
|
||||
|
||||
<h2 id="Appendix">Appendix</h2>
|
||||
|
||||
<h3 id="Type_unification_rules">Type unification rules</h3>
|
||||
|
||||
<p>
|
||||
The type unification rules describe if and how two types unify.
|
||||
The precise details are relevant for Go implementations,
|
||||
affect the specifics of error messages (such as whether
|
||||
a compiler reports a type inference or other error),
|
||||
and may explain why type inference fails in unusual code situations.
|
||||
But by and large these rules can be ignored when writing Go code:
|
||||
type inference is designed to mostly "work as expected",
|
||||
and the unification rules are fine-tuned accordingly.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Type unification is controlled by a <i>matching mode</i>, which may
|
||||
be <i>exact</i> or <i>loose</i>.
|
||||
As unification recursively descends a composite type structure,
|
||||
the matching mode used for elements of the type, the <i>element matching mode</i>,
|
||||
remains the same as the matching mode except when two types are unified for
|
||||
<a href="#Assignability">assignability</a> (<code>≡<sub>A</sub></code>):
|
||||
in this case, the matching mode is <i>loose</i> at the top level but
|
||||
then changes to <i>exact</i> for element types, reflecting the fact
|
||||
that types don't have to be identical to be assignable.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Two types that are not bound type parameters unify exactly if any of
|
||||
following conditions is true:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Both types are <a href="#Type_identity">identical</a>.
|
||||
</li>
|
||||
<li>
|
||||
Both types have identical structure and their element types
|
||||
unify exactly.
|
||||
</li>
|
||||
<li>
|
||||
Exactly one type is an <a href="#Type_inference">unbound</a>
|
||||
type parameter with a <a href="#Core_types">core type</a>,
|
||||
and that core type unifies with the other type per the
|
||||
unification rules for <code>≡<sub>A</sub></code>
|
||||
(loose unification at the top level and exact unification
|
||||
for element types).
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
If both types are bound type parameters, they unify per the given
|
||||
matching modes if:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Both type parameters are identical.
|
||||
</li>
|
||||
<li>
|
||||
At most one of the type parameters has a known type argument.
|
||||
In this case, the type parameters are <i>joined</i>:
|
||||
they both stand for the same type argument.
|
||||
If neither type parameter has a known type argument yet,
|
||||
a future type argument inferred for one the type parameters
|
||||
is simultaneously inferred for both of them.
|
||||
</li>
|
||||
<li>
|
||||
Both type parameters have a known type argument
|
||||
and the type arguments unify per the given matching modes.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
A single bound type parameter <code>P</code> and another type <code>T</code> unify
|
||||
per the given matching modes if:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<code>P</code> doesn't have a known type argument.
|
||||
In this case, <code>T</code> is inferred as the type argument for <code>P</code>.
|
||||
</li>
|
||||
<li>
|
||||
<code>P</code> does have a known type argument <code>A</code>,
|
||||
<code>A</code> and <code>T</code> unify per the given matching modes,
|
||||
and one of the following conditions is true:
|
||||
<ul>
|
||||
<li>
|
||||
Both <code>A</code> and <code>T</code> are interface types:
|
||||
In this case, if both <code>A</code> and <code>T</code> are
|
||||
also <a href="#Type_definitions">defined</a> types,
|
||||
they must be <a href="#Type_identity">identical</a>.
|
||||
Otherwise, if neither of them is a defined type, they must
|
||||
have the same number of methods
|
||||
(unification of <code>A</code> and <code>T</code> already
|
||||
established that the methods match).
|
||||
</li>
|
||||
<li>
|
||||
Neither <code>A</code> nor <code>T</code> are interface types:
|
||||
In this case, if <code>T</code> is a defined type, <code>T</code>
|
||||
replaces <code>A</code> as the inferred type argument for <code>P</code>.
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Finally, two types that are not bound type parameters unify loosely
|
||||
(and per the element matching mode) if:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Both types unify exactly.
|
||||
</li>
|
||||
<li>
|
||||
One type is a <a href="#Type_definitions">defined type</a>,
|
||||
the other type is a type literal, but not an interface,
|
||||
and their underlying types unify per the element matching mode.
|
||||
</li>
|
||||
<li>
|
||||
Both types are interfaces (but not type parameters) with
|
||||
identical <a href="#Interface_types">type terms</a>,
|
||||
both or neither embed the predeclared type
|
||||
<a href="#Predeclared_identifiers">comparable</a>,
|
||||
corresponding method types unify per the element matching mode,
|
||||
and the method set of one of the interfaces is a subset of
|
||||
the method set of the other interface.
|
||||
</li>
|
||||
<li>
|
||||
Only one type is an interface (but not a type parameter),
|
||||
corresponding methods of the two types unify per the element matching mode,
|
||||
and the method set of the interface is a subset of
|
||||
the method set of the other type.
|
||||
</li>
|
||||
<li>
|
||||
Both types have the same structure and their element types
|
||||
unify per the element matching mode.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -10,12 +10,12 @@ case "$GOWASIRUNTIME" in
|
||||
"wasmer")
|
||||
exec wasmer run --dir=/ --env PWD="$PWD" --env PATH="$PATH" ${GOWASIRUNTIMEARGS:-} "$1" -- "${@:2}"
|
||||
;;
|
||||
"wasmtime")
|
||||
exec wasmtime run --dir=/ --env PWD="$PWD" --env PATH="$PATH" --max-wasm-stack 1048576 ${GOWASIRUNTIMEARGS:-} "$1" -- "${@:2}"
|
||||
;;
|
||||
"wazero" | "")
|
||||
"wazero")
|
||||
exec wazero run -mount /:/ -env-inherit -cachedir "${TMPDIR:-/tmp}"/wazero ${GOWASIRUNTIMEARGS:-} "$1" "${@:2}"
|
||||
;;
|
||||
"wasmtime" | "")
|
||||
exec wasmtime run --dir=/ --env PWD="$PWD" --env PATH="$PATH" --max-wasm-stack 1048576 ${GOWASIRUNTIMEARGS:-} "$1" -- "${@:2}"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown Go WASI runtime specified: $GOWASIRUNTIME"
|
||||
exit 1
|
||||
|
||||
40
src/cmd/asm/internal/asm/testdata/riscv64.s
vendored
40
src/cmd/asm/internal/asm/testdata/riscv64.s
vendored
@@ -183,28 +183,28 @@ start:
|
||||
// 8.2: Load-Reserved/Store-Conditional
|
||||
LRW (X5), X6 // 2fa30214
|
||||
LRD (X5), X6 // 2fb30214
|
||||
SCW X5, (X6), X7 // af23531c
|
||||
SCD X5, (X6), X7 // af33531c
|
||||
SCW X5, (X6), X7 // af23531a
|
||||
SCD X5, (X6), X7 // af33531a
|
||||
|
||||
// 8.3: Atomic Memory Operations
|
||||
AMOSWAPW X5, (X6), X7 // af23530c
|
||||
AMOSWAPD X5, (X6), X7 // af33530c
|
||||
AMOADDW X5, (X6), X7 // af235304
|
||||
AMOADDD X5, (X6), X7 // af335304
|
||||
AMOANDW X5, (X6), X7 // af235364
|
||||
AMOANDD X5, (X6), X7 // af335364
|
||||
AMOORW X5, (X6), X7 // af235344
|
||||
AMOORD X5, (X6), X7 // af335344
|
||||
AMOXORW X5, (X6), X7 // af235324
|
||||
AMOXORD X5, (X6), X7 // af335324
|
||||
AMOMAXW X5, (X6), X7 // af2353a4
|
||||
AMOMAXD X5, (X6), X7 // af3353a4
|
||||
AMOMAXUW X5, (X6), X7 // af2353e4
|
||||
AMOMAXUD X5, (X6), X7 // af3353e4
|
||||
AMOMINW X5, (X6), X7 // af235384
|
||||
AMOMIND X5, (X6), X7 // af335384
|
||||
AMOMINUW X5, (X6), X7 // af2353c4
|
||||
AMOMINUD X5, (X6), X7 // af3353c4
|
||||
AMOSWAPW X5, (X6), X7 // af23530e
|
||||
AMOSWAPD X5, (X6), X7 // af33530e
|
||||
AMOADDW X5, (X6), X7 // af235306
|
||||
AMOADDD X5, (X6), X7 // af335306
|
||||
AMOANDW X5, (X6), X7 // af235366
|
||||
AMOANDD X5, (X6), X7 // af335366
|
||||
AMOORW X5, (X6), X7 // af235346
|
||||
AMOORD X5, (X6), X7 // af335346
|
||||
AMOXORW X5, (X6), X7 // af235326
|
||||
AMOXORD X5, (X6), X7 // af335326
|
||||
AMOMAXW X5, (X6), X7 // af2353a6
|
||||
AMOMAXD X5, (X6), X7 // af3353a6
|
||||
AMOMAXUW X5, (X6), X7 // af2353e6
|
||||
AMOMAXUD X5, (X6), X7 // af3353e6
|
||||
AMOMINW X5, (X6), X7 // af235386
|
||||
AMOMIND X5, (X6), X7 // af335386
|
||||
AMOMINUW X5, (X6), X7 // af2353c6
|
||||
AMOMINUD X5, (X6), X7 // af3353c6
|
||||
|
||||
// 10.1: Base Counters and Timers
|
||||
RDCYCLE X5 // f32200c0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package cgotest
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lm
|
||||
#cgo !darwin LDFLAGS: -lm
|
||||
#include <math.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package issue8756
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lm
|
||||
#cgo !darwin LDFLAGS: -lm
|
||||
#include <math.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
@@ -23,7 +23,7 @@ package cgotest
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#cgo LDFLAGS: -lm
|
||||
#cgo !darwin LDFLAGS: -lm
|
||||
|
||||
#ifndef WIN32
|
||||
#include <pthread.h>
|
||||
|
||||
@@ -110,11 +110,11 @@ type Config struct {
|
||||
// type checker will initialize this field with a newly created context.
|
||||
Context *Context
|
||||
|
||||
// GoVersion describes the accepted Go language version. The string
|
||||
// must follow the format "go%d.%d" (e.g. "go1.12") or ist must be
|
||||
// empty; an empty string disables Go language version checks.
|
||||
// If the format is invalid, invoking the type checker will cause a
|
||||
// panic.
|
||||
// GoVersion describes the accepted Go language version. The string must
|
||||
// start with a prefix of the form "go%d.%d" (e.g. "go1.20", "go1.21rc1", or
|
||||
// "go1.21.0") or it must be empty; an empty string disables Go language
|
||||
// version checks. If the format is invalid, invoking the type checker will
|
||||
// result in an error.
|
||||
GoVersion string
|
||||
|
||||
// If IgnoreFuncBodies is set, function bodies are not
|
||||
|
||||
@@ -576,6 +576,11 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||
// If nargs == 1, make sure x.mode is either a value or a constant.
|
||||
if x.mode != constant_ {
|
||||
x.mode = value
|
||||
// A value must not be untyped.
|
||||
check.assignment(x, &emptyInterface, "argument to "+bin.name)
|
||||
if x.mode == invalid {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Use the final type computed above for all arguments.
|
||||
|
||||
30
src/cmd/dist/test.go
vendored
30
src/cmd/dist/test.go
vendored
@@ -91,6 +91,29 @@ type work struct {
|
||||
end chan bool
|
||||
}
|
||||
|
||||
// printSkip prints a skip message for all of work.
|
||||
func (w *work) printSkip(t *tester, msg string) {
|
||||
if t.json {
|
||||
type event struct {
|
||||
Time time.Time
|
||||
Action string
|
||||
Package string
|
||||
Output string `json:",omitempty"`
|
||||
}
|
||||
enc := json.NewEncoder(&w.out)
|
||||
ev := event{Time: time.Now(), Package: w.dt.name, Action: "start"}
|
||||
enc.Encode(ev)
|
||||
ev.Action = "output"
|
||||
ev.Output = msg
|
||||
enc.Encode(ev)
|
||||
ev.Action = "skip"
|
||||
ev.Output = ""
|
||||
enc.Encode(ev)
|
||||
return
|
||||
}
|
||||
fmt.Fprintln(&w.out, msg)
|
||||
}
|
||||
|
||||
// A distTest is a test run by dist test.
|
||||
// Each test has a unique name and belongs to a group (heading)
|
||||
type distTest struct {
|
||||
@@ -405,6 +428,9 @@ func (opts *goTest) buildArgs(t *tester) (build, run, pkgs, testFlags []string,
|
||||
if opts.timeout != 0 {
|
||||
d := opts.timeout * time.Duration(t.timeoutScale)
|
||||
run = append(run, "-timeout="+d.String())
|
||||
} else if t.timeoutScale != 1 {
|
||||
const goTestDefaultTimeout = 10 * time.Minute // Default value of go test -timeout flag.
|
||||
run = append(run, "-timeout="+(goTestDefaultTimeout*time.Duration(t.timeoutScale)).String())
|
||||
}
|
||||
if opts.short || t.short {
|
||||
run = append(run, "-short")
|
||||
@@ -1235,7 +1261,7 @@ func (t *tester) runPending(nextTest *distTest) {
|
||||
go func(w *work) {
|
||||
if !<-w.start {
|
||||
timelog("skip", w.dt.name)
|
||||
w.out.WriteString("skipped due to earlier error\n")
|
||||
w.printSkip(t, "skipped due to earlier error")
|
||||
} else {
|
||||
timelog("start", w.dt.name)
|
||||
w.err = w.cmd.Run()
|
||||
@@ -1246,7 +1272,7 @@ func (t *tester) runPending(nextTest *distTest) {
|
||||
if isUnsupportedVMASize(w) {
|
||||
timelog("skip", w.dt.name)
|
||||
w.out.Reset()
|
||||
w.out.WriteString("skipped due to unsupported VMA\n")
|
||||
w.printSkip(t, "skipped due to unsupported VMA")
|
||||
w.err = nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,6 +473,7 @@ func recompileForTest(pmain, preal, ptest, pxtest *Package) *PackageError {
|
||||
p.Target = ""
|
||||
p.Internal.BuildInfo = nil
|
||||
p.Internal.ForceLibrary = true
|
||||
p.Internal.PGOProfile = preal.Internal.PGOProfile
|
||||
}
|
||||
|
||||
// Update p.Internal.Imports to use test copies.
|
||||
@@ -496,6 +497,11 @@ func recompileForTest(pmain, preal, ptest, pxtest *Package) *PackageError {
|
||||
if p.Name == "main" && p != pmain && p != ptest {
|
||||
split()
|
||||
}
|
||||
// Split and attach PGO information to test dependencies if preal
|
||||
// is built with PGO.
|
||||
if preal.Internal.PGOProfile != "" && p.Internal.PGOProfile == "" {
|
||||
split()
|
||||
}
|
||||
}
|
||||
|
||||
// Do search to find cycle.
|
||||
|
||||
@@ -110,7 +110,13 @@ func ListModules(ctx context.Context, args []string, mode ListMode, reuseFile st
|
||||
|
||||
if err == nil {
|
||||
requirements = rs
|
||||
if !ExplicitWriteGoMod {
|
||||
// TODO(#61605): The extra ListU clause fixes a problem with Go 1.21rc3
|
||||
// where "go mod tidy" and "go list -m -u all" fight over whether the go.sum
|
||||
// should be considered up-to-date. The fix for now is to always treat the
|
||||
// go.sum as up-to-date during list -m -u. Probably the right fix is more targeted,
|
||||
// but in general list -u is looking up other checksums in the checksum database
|
||||
// that won't be necessary later, so it makes sense not to write the go.sum back out.
|
||||
if !ExplicitWriteGoMod && mode&ListU == 0 {
|
||||
err = commitRequirements(ctx, WriteOpts{})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ func init() {
|
||||
cf.String("run", "", "")
|
||||
cf.Bool("short", false, "")
|
||||
cf.String("skip", "", "")
|
||||
cf.DurationVar(&testTimeout, "timeout", 10*time.Minute, "")
|
||||
cf.DurationVar(&testTimeout, "timeout", 10*time.Minute, "") // known to cmd/dist
|
||||
cf.String("fuzztime", "", "")
|
||||
cf.String("fuzzminimizetime", "", "")
|
||||
cf.StringVar(&testTrace, "trace", "", "")
|
||||
|
||||
@@ -175,7 +175,11 @@ func main() {
|
||||
if used > 0 {
|
||||
helpArg += " " + strings.Join(args[:used], " ")
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "go %s: unknown command\nRun 'go help%s' for usage.\n", cfg.CmdName, helpArg)
|
||||
cmdName := cfg.CmdName
|
||||
if cmdName == "" {
|
||||
cmdName = args[0]
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "go %s: unknown command\nRun 'go help%s' for usage.\n", cmdName, helpArg)
|
||||
base.SetExitStatus(2)
|
||||
base.Exit()
|
||||
}
|
||||
|
||||
@@ -45,6 +45,12 @@ stderr 'compile.*-pgoprofile=.*b(/|\\\\)default\.pgo.*b(/|\\\\)b_test\.go'
|
||||
stderr 'compile.*-pgoprofile=.*b(/|\\\\)default\.pgo.*dep(/|\\\\)dep\.go'
|
||||
! stderr 'compile.*-pgoprofile=.*nopgo(/|\\\\)nopgo_test\.go'
|
||||
|
||||
# test-only dependencies also have profiles attached
|
||||
stderr 'compile.*-pgoprofile=.*a(/|\\\\)default\.pgo.*testdep(/|\\\\)testdep\.go'
|
||||
stderr 'compile.*-pgoprofile=.*b(/|\\\\)default\.pgo.*testdep(/|\\\\)testdep\.go'
|
||||
stderr 'compile.*-pgoprofile=.*a(/|\\\\)default\.pgo.*testdep2(/|\\\\)testdep2\.go'
|
||||
stderr 'compile.*-pgoprofile=.*b(/|\\\\)default\.pgo.*testdep2(/|\\\\)testdep2\.go'
|
||||
|
||||
# go list -deps prints packages built multiple times.
|
||||
go list -pgo=auto -deps ./a ./b ./nopgo
|
||||
stdout 'test/dep \[test/a\]'
|
||||
@@ -66,6 +72,7 @@ func main() {}
|
||||
-- a/a_test.go --
|
||||
package main
|
||||
import "testing"
|
||||
import _ "test/testdep"
|
||||
func TestA(*testing.T) {}
|
||||
-- a/default.pgo --
|
||||
-- b/b.go --
|
||||
@@ -76,6 +83,7 @@ func main() {}
|
||||
-- b/b_test.go --
|
||||
package main
|
||||
import "testing"
|
||||
import _ "test/testdep"
|
||||
func TestB(*testing.T) {}
|
||||
-- b/default.pgo --
|
||||
-- nopgo/nopgo.go --
|
||||
@@ -94,3 +102,8 @@ import _ "test/dep3"
|
||||
package dep2
|
||||
-- dep3/dep3.go --
|
||||
package dep3
|
||||
-- testdep/testdep.go --
|
||||
package testdep
|
||||
import _ "test/testdep2"
|
||||
-- testdep2/testdep2.go --
|
||||
package testdep2
|
||||
|
||||
2
src/cmd/go/testdata/script/go_badcmd.txt
vendored
Normal file
2
src/cmd/go/testdata/script/go_badcmd.txt
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
! go asdf
|
||||
stderr '^go asdf: unknown command'
|
||||
@@ -2067,17 +2067,22 @@ func instructionsForProg(p *obj.Prog) []*instruction {
|
||||
return instructionsForStore(p, ins.as, p.To.Reg)
|
||||
|
||||
case ALRW, ALRD:
|
||||
// Set aq to use acquire access ordering, which matches Go's memory requirements.
|
||||
// Set aq to use acquire access ordering
|
||||
ins.funct7 = 2
|
||||
ins.rs1, ins.rs2 = uint32(p.From.Reg), REG_ZERO
|
||||
|
||||
case AADDI, AANDI, AORI, AXORI:
|
||||
inss = instructionsForOpImmediate(p, ins.as, p.Reg)
|
||||
|
||||
case ASCW, ASCD, AAMOSWAPW, AAMOSWAPD, AAMOADDW, AAMOADDD, AAMOANDW, AAMOANDD, AAMOORW, AAMOORD,
|
||||
case ASCW, ASCD:
|
||||
// Set release access ordering
|
||||
ins.funct7 = 1
|
||||
ins.rd, ins.rs1, ins.rs2 = uint32(p.RegTo2), uint32(p.To.Reg), uint32(p.From.Reg)
|
||||
|
||||
case AAMOSWAPW, AAMOSWAPD, AAMOADDW, AAMOADDD, AAMOANDW, AAMOANDD, AAMOORW, AAMOORD,
|
||||
AAMOXORW, AAMOXORD, AAMOMINW, AAMOMIND, AAMOMINUW, AAMOMINUD, AAMOMAXW, AAMOMAXD, AAMOMAXUW, AAMOMAXUD:
|
||||
// Set aq to use acquire access ordering, which matches Go's memory requirements.
|
||||
ins.funct7 = 2
|
||||
// Set aqrl to use acquire & release access ordering
|
||||
ins.funct7 = 3
|
||||
ins.rd, ins.rs1, ins.rs2 = uint32(p.RegTo2), uint32(p.To.Reg), uint32(p.From.Reg)
|
||||
|
||||
case AECALL, AEBREAK, ARDCYCLE, ARDTIME, ARDINSTRET:
|
||||
|
||||
@@ -446,7 +446,7 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sy
|
||||
rs := r.Xsym
|
||||
rt := r.Type
|
||||
|
||||
if ldr.SymType(rs) == sym.SHOSTOBJ || rt == objabi.R_PCREL || rt == objabi.R_GOTPCREL || rt == objabi.R_CALL {
|
||||
if rt == objabi.R_PCREL || rt == objabi.R_GOTPCREL || rt == objabi.R_CALL || ldr.SymType(rs) == sym.SHOSTOBJ || ldr.SymType(s) == sym.SINITARR {
|
||||
if ldr.SymDynid(rs) < 0 {
|
||||
ldr.Errorf(s, "reloc %d (%s) to non-macho symbol %s type=%d (%s)", rt, sym.RelocName(arch, rt), ldr.SymName(rs), ldr.SymType(rs), ldr.SymType(rs))
|
||||
return false
|
||||
|
||||
@@ -545,10 +545,11 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sy
|
||||
}
|
||||
}
|
||||
|
||||
if ldr.SymType(rs) == sym.SHOSTOBJ || rt == objabi.R_CALLARM64 ||
|
||||
if rt == objabi.R_CALLARM64 ||
|
||||
rt == objabi.R_ARM64_PCREL_LDST8 || rt == objabi.R_ARM64_PCREL_LDST16 ||
|
||||
rt == objabi.R_ARM64_PCREL_LDST32 || rt == objabi.R_ARM64_PCREL_LDST64 ||
|
||||
rt == objabi.R_ADDRARM64 || rt == objabi.R_ARM64_GOTPCREL {
|
||||
rt == objabi.R_ADDRARM64 || rt == objabi.R_ARM64_GOTPCREL ||
|
||||
ldr.SymType(rs) == sym.SHOSTOBJ || ldr.SymType(s) == sym.SINITARR {
|
||||
if ldr.SymDynid(rs) < 0 {
|
||||
ldr.Errorf(s, "reloc %d (%s) to non-macho symbol %s type=%d (%s)", rt, sym.RelocName(arch, rt), ldr.SymName(rs), ldr.SymType(rs), ldr.SymType(rs))
|
||||
return false
|
||||
|
||||
@@ -368,7 +368,9 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) {
|
||||
o = 0
|
||||
}
|
||||
} else if target.IsDarwin() {
|
||||
if ldr.SymType(rs) != sym.SHOSTOBJ {
|
||||
if ldr.SymType(rs) != sym.SHOSTOBJ && ldr.SymType(s) != sym.SINITARR {
|
||||
// ld-prime drops the offset in data for SINITARR. We need to use
|
||||
// symbol-targeted relocation. See also machoreloc1.
|
||||
o += ldr.SymValue(rs)
|
||||
}
|
||||
} else if target.IsWindows() {
|
||||
|
||||
@@ -833,9 +833,9 @@ func asmbMacho(ctxt *Link) {
|
||||
ml.data[2] = uint32(linkoff + s1 + s2 + s3 + s4 + s5) /* stroff */
|
||||
ml.data[3] = uint32(s6) /* strsize */
|
||||
|
||||
machodysymtab(ctxt, linkoff+s1+s2)
|
||||
|
||||
if ctxt.LinkMode != LinkExternal {
|
||||
machodysymtab(ctxt, linkoff+s1+s2)
|
||||
|
||||
ml := newMachoLoad(ctxt.Arch, LC_LOAD_DYLINKER, 6)
|
||||
ml.data[0] = 12 /* offset to string */
|
||||
stringtouint32(ml.data[1:], "/usr/lib/dyld")
|
||||
|
||||
@@ -936,6 +936,10 @@ func (hs *clientHandshakeState) sendFinished(out []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// maxRSAKeySize is the maximum RSA key size in bits that we are willing
|
||||
// to verify the signatures of during a TLS handshake.
|
||||
const maxRSAKeySize = 8192
|
||||
|
||||
// verifyServerCertificate parses and verifies the provided chain, setting
|
||||
// c.verifiedChains and c.peerCertificates or sending the appropriate alert.
|
||||
func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
|
||||
@@ -947,6 +951,10 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
|
||||
c.sendAlert(alertBadCertificate)
|
||||
return errors.New("tls: failed to parse certificate from server: " + err.Error())
|
||||
}
|
||||
if cert.cert.PublicKeyAlgorithm == x509.RSA && cert.cert.PublicKey.(*rsa.PublicKey).N.BitLen() > maxRSAKeySize {
|
||||
c.sendAlert(alertBadCertificate)
|
||||
return fmt.Errorf("tls: server sent certificate containing RSA key larger than %d bits", maxRSAKeySize)
|
||||
}
|
||||
activeHandles[i] = cert
|
||||
certs[i] = cert.cert
|
||||
}
|
||||
|
||||
@@ -2721,3 +2721,81 @@ func testTLS13OnlyClientHelloCipherSuite(t *testing.T, ciphers []uint16) {
|
||||
t.Fatalf("handshake failed: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// discardConn wraps a net.Conn but discards all writes, but reports that they happened.
|
||||
type discardConn struct {
|
||||
net.Conn
|
||||
}
|
||||
|
||||
func (dc *discardConn) Write(data []byte) (int, error) {
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
// largeRSAKeyCertPEM contains a 8193 bit RSA key
|
||||
const largeRSAKeyCertPEM = `-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
u58=
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
func TestHandshakeRSATooBig(t *testing.T) {
|
||||
testCert, _ := pem.Decode([]byte(largeRSAKeyCertPEM))
|
||||
|
||||
c := &Conn{conn: &discardConn{}, config: testConfig.Clone()}
|
||||
|
||||
expectedErr := "tls: server sent certificate containing RSA key larger than 8192 bits"
|
||||
err := c.verifyServerCertificate([][]byte{testCert.Bytes})
|
||||
if err == nil || err.Error() != expectedErr {
|
||||
t.Errorf("Conn.verifyServerCertificate unexpected error: want %q, got %q", expectedErr, err)
|
||||
}
|
||||
|
||||
expectedErr = "tls: client sent certificate containing RSA key larger than 8192 bits"
|
||||
err = c.processCertsFromClient(Certificate{Certificate: [][]byte{testCert.Bytes}})
|
||||
if err == nil || err.Error() != expectedErr {
|
||||
t.Errorf("Conn.processCertsFromClient unexpected error: want %q, got %q", expectedErr, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -864,6 +864,10 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error {
|
||||
c.sendAlert(alertBadCertificate)
|
||||
return errors.New("tls: failed to parse client certificate: " + err.Error())
|
||||
}
|
||||
if certs[i].PublicKeyAlgorithm == x509.RSA && certs[i].PublicKey.(*rsa.PublicKey).N.BitLen() > maxRSAKeySize {
|
||||
c.sendAlert(alertBadCertificate)
|
||||
return fmt.Errorf("tls: client sent certificate containing RSA key larger than %d bits", maxRSAKeySize)
|
||||
}
|
||||
}
|
||||
|
||||
if len(certs) == 0 && requiresClientCert(c.config.ClientAuth) {
|
||||
|
||||
@@ -246,10 +246,15 @@ func (q *QUICConn) HandleData(level QUICEncryptionLevel, data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type QUICSessionTicketOptions struct {
|
||||
// EarlyData specifies whether the ticket may be used for 0-RTT.
|
||||
EarlyData bool
|
||||
}
|
||||
|
||||
// SendSessionTicket sends a session ticket to the client.
|
||||
// It produces connection events, which may be read with NextEvent.
|
||||
// Currently, it can only be called once.
|
||||
func (q *QUICConn) SendSessionTicket(earlyData bool) error {
|
||||
func (q *QUICConn) SendSessionTicket(opts QUICSessionTicketOptions) error {
|
||||
c := q.conn
|
||||
if !c.isHandshakeComplete.Load() {
|
||||
return quicError(errors.New("tls: SendSessionTicket called before handshake completed"))
|
||||
@@ -261,7 +266,7 @@ func (q *QUICConn) SendSessionTicket(earlyData bool) error {
|
||||
return quicError(errors.New("tls: SendSessionTicket called multiple times"))
|
||||
}
|
||||
q.sessionTicketSent = true
|
||||
return quicError(c.sendSessionTicket(earlyData))
|
||||
return quicError(c.sendSessionTicket(opts.EarlyData))
|
||||
}
|
||||
|
||||
// ConnectionState returns basic TLS details about the connection.
|
||||
|
||||
@@ -125,7 +125,8 @@ func runTestQUICConnection(ctx context.Context, cli, srv *testQUICConn, onHandle
|
||||
case QUICHandshakeDone:
|
||||
a.complete = true
|
||||
if a == srv {
|
||||
if err := srv.conn.SendSessionTicket(false); err != nil {
|
||||
opts := QUICSessionTicketOptions{}
|
||||
if err := srv.conn.SendSessionTicket(opts); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,11 +114,11 @@ type Config struct {
|
||||
// type checker will initialize this field with a newly created context.
|
||||
Context *Context
|
||||
|
||||
// GoVersion describes the accepted Go language version. The string
|
||||
// must follow the format "go%d.%d" (e.g. "go1.12") or it must be
|
||||
// empty; an empty string disables Go language version checks.
|
||||
// If the format is invalid, invoking the type checker will cause a
|
||||
// panic.
|
||||
// GoVersion describes the accepted Go language version. The string must
|
||||
// start with a prefix of the form "go%d.%d" (e.g. "go1.20", "go1.21rc1", or
|
||||
// "go1.21.0") or it must be empty; an empty string disables Go language
|
||||
// version checks. If the format is invalid, invoking the type checker will
|
||||
// result in an error.
|
||||
GoVersion string
|
||||
|
||||
// If IgnoreFuncBodies is set, function bodies are not
|
||||
|
||||
@@ -575,6 +575,11 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||
// If nargs == 1, make sure x.mode is either a value or a constant.
|
||||
if x.mode != constant_ {
|
||||
x.mode = value
|
||||
// A value must not be untyped.
|
||||
check.assignment(x, &emptyInterface, "argument to "+bin.name)
|
||||
if x.mode == invalid {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Use the final type computed above for all arguments.
|
||||
|
||||
9
src/internal/types/testdata/fixedbugs/issue61486.go
vendored
Normal file
9
src/internal/types/testdata/fixedbugs/issue61486.go
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright 2023 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 _(s uint) {
|
||||
_ = min(1 << s)
|
||||
}
|
||||
@@ -23,7 +23,6 @@ type Level int
|
||||
// First, we wanted the default level to be Info, Since Levels are ints, Info is
|
||||
// the default value for int, zero.
|
||||
//
|
||||
|
||||
// Second, we wanted to make it easy to use levels to specify logger verbosity.
|
||||
// Since a larger level means a more severe event, a logger that accepts events
|
||||
// with smaller (or more negative) level means a more verbose logger. Logger
|
||||
|
||||
@@ -5,34 +5,6 @@
|
||||
// Package maps defines various functions useful with maps of any type.
|
||||
package maps
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// keys is implemented in the runtime package.
|
||||
//
|
||||
//go:noescape
|
||||
func keys(m any, slice unsafe.Pointer)
|
||||
|
||||
// Keys returns the keys of the map m.
|
||||
// The keys will be in an indeterminate order.
|
||||
func Keys[M ~map[K]V, K comparable, V any](m M) []K {
|
||||
r := make([]K, 0, len(m))
|
||||
keys(m, unsafe.Pointer(&r))
|
||||
return r
|
||||
}
|
||||
|
||||
// values is implemented in the runtime package.
|
||||
//
|
||||
//go:noescape
|
||||
func values(m any, slice unsafe.Pointer)
|
||||
|
||||
// Values returns the values of the map m.
|
||||
// The values will be in an indeterminate order.
|
||||
func Values[M ~map[K]V, K comparable, V any](m M) []V {
|
||||
r := make([]V, 0, len(m))
|
||||
values(m, unsafe.Pointer(&r))
|
||||
return r
|
||||
}
|
||||
|
||||
// Equal reports whether two maps contain the same key/value pairs.
|
||||
// Values are compared using ==.
|
||||
func Equal[M1, M2 ~map[K]V, K, V comparable](m1 M1, m2 M2) bool {
|
||||
|
||||
@@ -6,87 +6,13 @@ package maps
|
||||
|
||||
import (
|
||||
"math"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var m1 = map[int]int{1: 2, 2: 4, 4: 8, 8: 16}
|
||||
var m2 = map[int]string{1: "2", 2: "4", 4: "8", 8: "16"}
|
||||
|
||||
func keysForBenchmarking[M ~map[K]V, K comparable, V any](m M, s []K) {
|
||||
keys(m, unsafe.Pointer(&s))
|
||||
}
|
||||
|
||||
func TestKeys(t *testing.T) {
|
||||
want := []int{1, 2, 4, 8}
|
||||
|
||||
got1 := Keys(m1)
|
||||
sort.Ints(got1)
|
||||
if !slices.Equal(got1, want) {
|
||||
t.Errorf("Keys(%v) = %v, want %v", m1, got1, want)
|
||||
}
|
||||
|
||||
got2 := Keys(m2)
|
||||
sort.Ints(got2)
|
||||
if !slices.Equal(got2, want) {
|
||||
t.Errorf("Keys(%v) = %v, want %v", m2, got2, want)
|
||||
}
|
||||
|
||||
// test for oldbucket code path
|
||||
// We grow from 128 to 256 buckets at size 832 (6.5 * 128).
|
||||
// Then we have to evacuate 128 buckets, which means we'll be done evacuation at 832+128=960 elements inserted.
|
||||
// so 840 is a good number to test for oldbucket code path.
|
||||
var want3 []int
|
||||
var m = make(map[int]int)
|
||||
for i := 0; i < 840; i++ {
|
||||
want3 = append(want3, i)
|
||||
m[i] = i * i
|
||||
}
|
||||
|
||||
got3 := Keys(m)
|
||||
sort.Ints(got3)
|
||||
if !slices.Equal(got3, want3) {
|
||||
t.Errorf("Keys(%v) = %v, want %v", m, got3, want3)
|
||||
}
|
||||
}
|
||||
|
||||
func valuesForBenchmarking[M ~map[K]V, K comparable, V any](m M, s []V) {
|
||||
values(m, unsafe.Pointer(&s))
|
||||
}
|
||||
|
||||
func TestValues(t *testing.T) {
|
||||
got1 := Values(m1)
|
||||
want1 := []int{2, 4, 8, 16}
|
||||
sort.Ints(got1)
|
||||
if !slices.Equal(got1, want1) {
|
||||
t.Errorf("Values(%v) = %v, want %v", m1, got1, want1)
|
||||
}
|
||||
|
||||
got2 := Values(m2)
|
||||
want2 := []string{"16", "2", "4", "8"}
|
||||
sort.Strings(got2)
|
||||
if !slices.Equal(got2, want2) {
|
||||
t.Errorf("Values(%v) = %v, want %v", m2, got2, want2)
|
||||
}
|
||||
|
||||
//test for oldbucket code path
|
||||
var want3 []int
|
||||
var m = make(map[int]int)
|
||||
for i := 0; i < 840; i++ {
|
||||
want3 = append(want3, i*i)
|
||||
m[i] = i * i
|
||||
}
|
||||
|
||||
got3 := Values(m)
|
||||
sort.Ints(got3)
|
||||
if !slices.Equal(got3, want3) {
|
||||
t.Errorf("Values(%v) = %v, want %v", m, got3, want3)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEqual(t *testing.T) {
|
||||
if !Equal(m1, m1) {
|
||||
t.Errorf("Equal(%v, %v) = false, want true", m1, m1)
|
||||
@@ -256,29 +182,3 @@ func TestCloneWithMapAssign(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkKeys(b *testing.B) {
|
||||
m := make(map[int]int, 1000000)
|
||||
for i := 0; i < 1000000; i++ {
|
||||
m[i] = i
|
||||
}
|
||||
b.ResetTimer()
|
||||
|
||||
slice := make([]int, 0, len(m))
|
||||
for i := 0; i < b.N; i++ {
|
||||
keysForBenchmarking(m, slice)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkValues(b *testing.B) {
|
||||
m := make(map[int]int, 1000000)
|
||||
for i := 0; i < 1000000; i++ {
|
||||
m[i] = i
|
||||
}
|
||||
b.ResetTimer()
|
||||
|
||||
slice := make([]int, 0, len(m))
|
||||
for i := 0; i < b.N; i++ {
|
||||
valuesForBenchmarking(m, slice)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,13 +349,8 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
|
||||
|
||||
w.WriteHeader(code)
|
||||
|
||||
if r.Method != MethodHead {
|
||||
if sendSize == size {
|
||||
// use Copy in the non-range case to make use of WriterTo if available
|
||||
io.Copy(w, sendContent)
|
||||
} else {
|
||||
io.CopyN(w, sendContent, sendSize)
|
||||
}
|
||||
if r.Method != "HEAD" {
|
||||
io.CopyN(w, sendContent, sendSize)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -924,7 +924,6 @@ func testServeContent(t *testing.T, mode testMode) {
|
||||
wantContentType string
|
||||
wantContentRange string
|
||||
wantStatus int
|
||||
wantContent []byte
|
||||
}
|
||||
htmlModTime := mustStat(t, "testdata/index.html").ModTime()
|
||||
tests := map[string]testCase{
|
||||
@@ -1140,24 +1139,6 @@ func testServeContent(t *testing.T, mode testMode) {
|
||||
wantStatus: 412,
|
||||
wantLastMod: htmlModTime.UTC().Format(TimeFormat),
|
||||
},
|
||||
"uses_writeTo_if_available_and_non-range": {
|
||||
content: &panicOnNonWriterTo{seekWriterTo: strings.NewReader("foobar")},
|
||||
serveContentType: "text/plain; charset=utf-8",
|
||||
wantContentType: "text/plain; charset=utf-8",
|
||||
wantStatus: StatusOK,
|
||||
wantContent: []byte("foobar"),
|
||||
},
|
||||
"do_not_use_writeTo_for_range_requests": {
|
||||
content: &panicOnWriterTo{ReadSeeker: strings.NewReader("foobar")},
|
||||
serveContentType: "text/plain; charset=utf-8",
|
||||
reqHeader: map[string]string{
|
||||
"Range": "bytes=0-4",
|
||||
},
|
||||
wantContentType: "text/plain; charset=utf-8",
|
||||
wantContentRange: "bytes 0-4/6",
|
||||
wantStatus: StatusPartialContent,
|
||||
wantContent: []byte("fooba"),
|
||||
},
|
||||
}
|
||||
for testName, tt := range tests {
|
||||
var content io.ReadSeeker
|
||||
@@ -1171,8 +1152,7 @@ func testServeContent(t *testing.T, mode testMode) {
|
||||
} else {
|
||||
content = tt.content
|
||||
}
|
||||
contentOut := &strings.Builder{}
|
||||
for _, method := range []string{MethodGet, MethodHead} {
|
||||
for _, method := range []string{"GET", "HEAD"} {
|
||||
//restore content in case it is consumed by previous method
|
||||
if content, ok := content.(*strings.Reader); ok {
|
||||
content.Seek(0, io.SeekStart)
|
||||
@@ -1198,8 +1178,7 @@ func testServeContent(t *testing.T, mode testMode) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
contentOut.Reset()
|
||||
io.Copy(contentOut, res.Body)
|
||||
io.Copy(io.Discard, res.Body)
|
||||
res.Body.Close()
|
||||
if res.StatusCode != tt.wantStatus {
|
||||
t.Errorf("test %q using %q: got status = %d; want %d", testName, method, res.StatusCode, tt.wantStatus)
|
||||
@@ -1213,28 +1192,10 @@ func testServeContent(t *testing.T, mode testMode) {
|
||||
if g, e := res.Header.Get("Last-Modified"), tt.wantLastMod; g != e {
|
||||
t.Errorf("test %q using %q: got last-modified = %q, want %q", testName, method, g, e)
|
||||
}
|
||||
if g, e := contentOut.String(), tt.wantContent; e != nil && method == MethodGet && g != string(e) {
|
||||
t.Errorf("test %q using %q: got unexpected content %q, want %q", testName, method, g, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type seekWriterTo interface {
|
||||
io.Seeker
|
||||
io.WriterTo
|
||||
}
|
||||
|
||||
type panicOnNonWriterTo struct {
|
||||
io.Reader
|
||||
seekWriterTo
|
||||
}
|
||||
|
||||
type panicOnWriterTo struct {
|
||||
io.ReadSeeker
|
||||
io.WriterTo
|
||||
}
|
||||
|
||||
// Issue 12991
|
||||
func TestServerFileStatError(t *testing.T) {
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
@@ -193,6 +193,9 @@ func TestInterfaceArrivalAndDepartureZoneCache(t *testing.T) {
|
||||
t.Skipf("test requires external command: %v", err)
|
||||
}
|
||||
if err := ti.setup(); err != nil {
|
||||
if e := err.Error(); strings.Contains(e, "Permission denied") {
|
||||
t.Skipf("permission denied, skipping test: %v", e)
|
||||
}
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ti.teardown()
|
||||
|
||||
@@ -44,9 +44,9 @@ func TestTCPEcho(t *testing.T) {
|
||||
subProcess.Env = append(os.Environ(), "GOOS=wasip1", "GOARCH=wasm")
|
||||
|
||||
switch os.Getenv("GOWASIRUNTIME") {
|
||||
case "wazero", "":
|
||||
case "wazero":
|
||||
subProcess.Env = append(subProcess.Env, "GOWASIRUNTIMEARGS=--listen="+host)
|
||||
case "wasmtime":
|
||||
case "wasmtime", "":
|
||||
subProcess.Env = append(subProcess.Env, "GOWASIRUNTIMEARGS=--tcplisten="+host)
|
||||
default:
|
||||
t.Skip("WASI runtime does not support sockets")
|
||||
|
||||
@@ -16,12 +16,17 @@ TEXT _rt0_amd64_windows(SB),NOSPLIT|NOFRAME,$-8
|
||||
// phase.
|
||||
// Leave space for four pointers on the stack as required
|
||||
// by the Windows amd64 calling convention.
|
||||
TEXT _rt0_amd64_windows_lib(SB),NOSPLIT|NOFRAME,$0x20
|
||||
TEXT _rt0_amd64_windows_lib(SB),NOSPLIT|NOFRAME,$40
|
||||
// Create a new thread to do the runtime initialization and return.
|
||||
MOVQ BX, 32(SP) // callee-saved, preserved across the CALL
|
||||
MOVQ SP, BX
|
||||
ANDQ $~15, SP // alignment as per Windows requirement
|
||||
MOVQ _cgo_sys_thread_create(SB), AX
|
||||
MOVQ $_rt0_amd64_windows_lib_go(SB), CX
|
||||
MOVQ $0, DX
|
||||
CALL AX
|
||||
MOVQ BX, SP
|
||||
MOVQ 32(SP), BX
|
||||
RET
|
||||
|
||||
TEXT _rt0_amd64_windows_lib_go(SB),NOSPLIT|NOFRAME,$0
|
||||
|
||||
Reference in New Issue
Block a user