Skip to content

Commit 7fed338

Browse files
griesemergopherbot
authored andcommitted
spec: update section on type unification for Go 1.21
This leaves the specific unification details out in favor of a (forthcoming) section in an appendix. Change-Id: If984c48bdf71c278e1a2759f9a18c51ef58df999 Reviewed-on: https://go-review.googlesource.com/c/go/+/507417 Reviewed-by: Robert Griesemer <[email protected]> Auto-Submit: Robert Griesemer <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> TryBot-Bypass: Robert Griesemer <[email protected]>
1 parent 12bd244 commit 7fed338

File tree

1 file changed

+85
-61
lines changed

1 file changed

+85
-61
lines changed

doc/go_spec.html

Lines changed: 85 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<!--{
22
"Title": "The Go Programming Language Specification",
3-
"Subtitle": "Version of July 20, 2023",
3+
"Subtitle": "Version of July 25, 2023",
44
"Path": "/ref/spec"
55
}-->
66

@@ -4457,7 +4457,7 @@ <h3 id="Type_inference">Type inference</h3>
44574457
(or <code>S ≡<sub>A</sub> Slice</code> for that matter),
44584458
where the <code><sub>A</sub></code> in <code><sub>A</sub></code>
44594459
indicates that the LHS and RHS types must match per assignability rules
4460-
(see the section on <a href="#Type_unification">type unifcation</a> for
4460+
(see the section on <a href="#Type_unification">type unification</a> for
44614461
details).
44624462
Similarly, the type parameter <code>S</code> must satisfy its constraint
44634463
<code>~[]E</code>. This can be expressed as <code>S ≡<sub>C</sub> ~[]E</code>
@@ -4618,84 +4618,108 @@ <h3 id="Type_inference">Type inference</h3>
46184618
<h4 id="Type_unification">Type unification</h4>
46194619

46204620
<p>
4621-
<em>
4622-
Note: This section is not up-to-date for Go 1.21.
4623-
</em>
4621+
Type inference solves type equations through <i>type unification</i>.
4622+
Type unification recursively compares the LHS and RHS types of an
4623+
equation, where either or both types may be or contain type parameters,
4624+
and looks for type arguments for those type parameters such that the LHS
4625+
and RHS match (become identical or assignment-compatible, depending on
4626+
context).
4627+
To that effect, type inference maintains a map of bound type parameters
4628+
to inferred type arguments.
4629+
Initially, the type parameters are known but the map is empty.
4630+
During type unification, if a new type argument <code>A</code> is inferred,
4631+
the respective mapping <code>P ➞ A</code> from type parameter to argument
4632+
is added to the map.
4633+
Conversely, when comparing types, a known type argument
4634+
(a type argument for which a map entry already exists)
4635+
takes the place of its corresponding type parameter.
4636+
As type inference progresses, the map is populated more and more
4637+
until all equations have been considered, or until unification fails.
4638+
Type inference succeeds if no unification step fails and the map has
4639+
an entry for each type parameter.
46244640
</p>
46254641

4626-
<p>
4627-
Type inference is based on <i>type unification</i>. A single unification step
4628-
applies to a <a href="#Type_inference">substitution map</a> and two types, either
4629-
or both of which may be or contain type parameters. The substitution map tracks
4630-
the known (explicitly provided or already inferred) type arguments: the map
4631-
contains an entry <code>P</code> &RightArrow; <code>A</code> for each type
4632-
parameter <code>P</code> and corresponding known type argument <code>A</code>.
4633-
During unification, known type arguments take the place of their corresponding type
4634-
parameters when comparing types. Unification is the process of finding substitution
4635-
map entries that make the two types equivalent.
4642+
</pre>
4643+
For example, given the type equation with the bound type parameter
4644+
<code>P</code>
46364645
</p>
46374646

4638-
<p>
4639-
For unification, two types that don't contain any type parameters from the current type
4640-
parameter list are <i>equivalent</i>
4641-
if they are identical, or if they are channel types that are identical ignoring channel
4642-
direction, or if their underlying types are equivalent.
4643-
</p>
4647+
<pre>
4648+
[10]struct{ elem P, list []P } ≡<sub>A</sub> [10]struct{ elem string; list []string }
4649+
</pre>
46444650

46454651
<p>
4646-
Unification works by comparing the structure of pairs of types: their structure
4647-
disregarding type parameters must be identical, and types other than type parameters
4648-
must be equivalent.
4649-
A type parameter in one type may match any complete subtype in the other type;
4650-
each successful match causes an entry to be added to the substitution map.
4651-
If the structure differs, or types other than type parameters are not equivalent,
4652-
unification fails.
4652+
type inference starts with an empty map.
4653+
Unification first compares the top-level structure of the LHS and RHS
4654+
types.
4655+
Both are arrays of the same length; they unify if the element types unify.
4656+
Both element types are structs; they unify if they have
4657+
the same number of fields with the same names and if the
4658+
field types unify.
4659+
The type argument for <code>P</code> is not known yet (there is no map entry),
4660+
so unifying <code>P</code> with <code>string</code> adds
4661+
the mapping <code>P ➞ string</code> to the map.
4662+
Unifying the types of the <code>list</code> field requires
4663+
unifying <code>[]P</code> and <code>[]string</code> and
4664+
thus <code>P</code> and <code>string</code>.
4665+
Since the type argument for <code>P</code> is known at this point
4666+
(there is a map entry for <code>P</code>), its type argument
4667+
<code>string</code> takes the place of <code>P</code>.
4668+
And since <code>string</code> is identical to <code>string</code>,
4669+
this unification step succeeds as well.
4670+
Unification of the LHS and RHS of the equation is now finished.
4671+
Type inference succeeds because there is only one type equation,
4672+
no unification step failed, and the map is fully populated.
46534673
</p>
46544674

4655-
<!--
4656-
TODO(gri) Somewhere we need to describe the process of adding an entry to the
4657-
substitution map: if the entry is already present, the type argument
4658-
values are themselves unified.
4659-
-->
4660-
46614675
<p>
4662-
For example, if <code>T1</code> and <code>T2</code> are type parameters,
4663-
<code>[]map[int]bool</code> can be unified with any of the following:
4676+
Unification uses a combination of <i>exact</i> and <i>loose</i>
4677+
Unification (see Appendix) depending on whether two types have
4678+
to be <a href="#Type_identity">identical</a> or simply
4679+
<a href="#Assignability">assignment-compatible</a>:
46644680
</p>
46654681

4666-
<pre>
4667-
[]map[int]bool // types are identical
4668-
T1 // adds T1 &RightArrow; []map[int]bool to substitution map
4669-
[]T1 // adds T1 &RightArrow; map[int]bool to substitution map
4670-
[]map[T1]T2 // adds T1 &RightArrow; int and T2 &RightArrow; bool to substitution map
4671-
</pre>
4672-
46734682
<p>
4674-
On the other hand, <code>[]map[int]bool</code> cannot be unified with any of
4683+
For an equation of the form <code>X ≡<sub>A</sub> Y</code>,
4684+
where <code>X</code> and <code>Y</code> are types involved
4685+
in an assignment (including parameter passing and return statements),
4686+
the top-level type structures may unify loosely but element types
4687+
must unify exactly, matching the rules for assignments.
46754688
</p>
46764689

4677-
<pre>
4678-
int // int is not a slice
4679-
struct{} // a struct is not a slice
4680-
[]struct{} // a struct is not a map
4681-
[]map[T1]string // map element types don't match
4682-
</pre>
4683-
46844690
<p>
4685-
As an exception to this general rule, because a <a href="#Type_definitions">defined type</a>
4686-
<code>D</code> and a type literal <code>L</code> are never equivalent,
4687-
unification compares the underlying type of <code>D</code> with <code>L</code> instead.
4688-
For example, given the defined type
4691+
For an equation of the form <code>P ≡<sub>C</sub> C</code>,
4692+
where <code>P</code> is a type parameter and <code>C</code>
4693+
its corresponding constraint, the unification rules are bit
4694+
more complicated:
46894695
</p>
46904696

4691-
<pre>
4692-
type Vector []float64
4693-
</pre>
4697+
<ul>
4698+
<li>
4699+
If <code>C</code> has a <a href="#Core_types">core type</a>
4700+
<code>core(C)</code>
4701+
and <code>P</code> has a known type argument <code>A</code>,
4702+
<code>core(C)</code> and <code>A</code> must unify loosely.
4703+
If <code>P</code> does not have a known type argument
4704+
and <code>C</code> contains exactly one type term <code>T</code>
4705+
that is not an underlying (tilde) type, unification adds the
4706+
mapping <code>P ➞ T</code> to the map.
4707+
</li>
4708+
<li>
4709+
If <code>C</code> does not have a core type
4710+
and <code>P</code> has a known type argument <code>A</code>,
4711+
<code>A</code> must have all methods of <code>C</code>, if any,
4712+
and corresponding method types must unify exactly.
4713+
</li>
4714+
</ul>
46944715

46954716
<p>
4696-
and the type literal <code>[]E</code>, unification compares <code>[]float64</code> with
4697-
<code>[]E</code> and adds an entry <code>E</code> &RightArrow; <code>float64</code> to
4698-
the substitution map.
4717+
When solving type equations from type constraints,
4718+
solving one equation may infer additional type arguments,
4719+
which in turn may enable solving other equations that depend
4720+
on those type arguments.
4721+
Type inference repeats type unification as long as new type
4722+
arguments are inferred.
46994723
</p>
47004724

47014725
<h3 id="Operators">Operators</h3>

0 commit comments

Comments
 (0)