|
1 | 1 | <!--{
|
2 | 2 | "Title": "The Go Programming Language Specification",
|
3 |
| - "Subtitle": "Version of July 20, 2023", |
| 3 | + "Subtitle": "Version of July 25, 2023", |
4 | 4 | "Path": "/ref/spec"
|
5 | 5 | }-->
|
6 | 6 |
|
@@ -4457,7 +4457,7 @@ <h3 id="Type_inference">Type inference</h3>
|
4457 | 4457 | (or <code>S ≡<sub>A</sub> Slice</code> for that matter),
|
4458 | 4458 | where the <code><sub>A</sub></code> in <code>≡<sub>A</sub></code>
|
4459 | 4459 | 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 |
4461 | 4461 | details).
|
4462 | 4462 | Similarly, the type parameter <code>S</code> must satisfy its constraint
|
4463 | 4463 | <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>
|
4618 | 4618 | <h4 id="Type_unification">Type unification</h4>
|
4619 | 4619 |
|
4620 | 4620 | <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. |
4624 | 4640 | </p>
|
4625 | 4641 |
|
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> → <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> |
4636 | 4645 | </p>
|
4637 | 4646 |
|
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> |
4644 | 4650 |
|
4645 | 4651 | <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. |
4653 | 4673 | </p>
|
4654 | 4674 |
|
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 |
| - |
4661 | 4675 | <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>: |
4664 | 4680 | </p>
|
4665 | 4681 |
|
4666 |
| -<pre> |
4667 |
| -[]map[int]bool // types are identical |
4668 |
| -T1 // adds T1 → []map[int]bool to substitution map |
4669 |
| -[]T1 // adds T1 → map[int]bool to substitution map |
4670 |
| -[]map[T1]T2 // adds T1 → int and T2 → bool to substitution map |
4671 |
| -</pre> |
4672 |
| - |
4673 | 4682 | <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. |
4675 | 4688 | </p>
|
4676 | 4689 |
|
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 |
| - |
4684 | 4690 | <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: |
4689 | 4695 | </p>
|
4690 | 4696 |
|
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> |
4694 | 4715 |
|
4695 | 4716 | <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> → <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. |
4699 | 4723 | </p>
|
4700 | 4724 |
|
4701 | 4725 | <h3 id="Operators">Operators</h3>
|
|
0 commit comments