spec: generalize method sets and interface types to type sets

This is the first of several CLs that update the existing
Go 1.17 spec for type parameters.

This CL updates the section on method sets and interface types.
It also adds "any", "comparable" to the list of predeclared
identifiers.

Change-Id: I0ce25dc02791c33150c0d949528512610faf3eab
Reviewed-on: https://go-review.googlesource.com/c/go/+/362999
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Robert Griesemer 2021-11-10 09:44:58 -08:00
parent d8f7a64519
commit f6647f2e3b

View file

@ -1,9 +1,18 @@
<!--{
"Title": "The Go Programming Language Specification",
"Subtitle": "Version of Oct 15, 2021",
"Subtitle": "Version of Nov 17, 2021",
"Path": "/ref/spec"
}-->
<h2>Draft Go 1.18 Specification - Work in Progress </h2>
<p>
<strong>
For the pre-Go1.18 spec see
<a href="/doc/go1.17_spec.html">The Go Programming Language Specification</a>.
</strong>
</p>
<h2 id="Introduction">Introduction</h2>
<p>
@ -266,7 +275,7 @@ The following character sequences represent <a href="#Operators">operators</a>
* ^ *= ^= &lt;- &gt; &gt;= { }
/ &lt;&lt; /= &lt;&lt;= ++ = := , ;
% &gt;&gt; %= &gt;&gt;= -- ! ... . :
&amp;^ &amp;^=
&amp;^ &amp;^= ~
</pre>
<h3 id="Integer_literals">Integer literals</h3>
@ -829,27 +838,41 @@ The underlying type of <code>[]B1</code>, <code>B3</code>, and <code>B4</code> i
</p>
<h3 id="Method_sets">Method sets</h3>
<p>
A type has a (possibly empty) <i>method set</i> associated with it.
The method set of an <a href="#Interface_types">interface type</a> is its interface.
The method set of any other type <code>T</code> consists of all
The <i>method set</i> of a type determines the methods that can be
<a href="#Calls">called</a> on an <a href="#Operands">operand</a> of that type.
Every type has a (possibly empty) method set associated with it:
</p>
<ul>
<li>The method set of a <a href="#Type_definitions">defined type</a> <code>T</code> consists of all
<a href="#Method_declarations">methods</a> declared with receiver type <code>T</code>.
The method set of the corresponding <a href="#Pointer_types">pointer type</a> <code>*T</code>
is the set of all methods declared with receiver <code>*T</code> or <code>T</code>
(that is, it also contains the method set of <code>T</code>).
Further rules apply to structs containing embedded fields, as described
in the section on <a href="#Struct_types">struct types</a>.
</li>
<li>
The method set of a <a href="#Pointer_types">pointer</a> <code>*T</code>
to a defined type <code>*T</code>
(where <code>T</code> is neither a pointer nor an interface)
is the set of all methods declared with receiver <code>*T</code> or <code>T</code>.
</li>
<li>The method set of an <a href="#Interface_types">interface type</a> is the intersection
of the method sets of each type in the interface's <a href="#Interface_types">type set</a>
(the resulting method set is usually just the set of declared methods in the interface).
</li>
</ul>
<p>
Further rules apply to structs (and pointer to structs) containing embedded fields,
as described in the section on <a href="#Struct_types">struct types</a>.
Any other type has an empty method set.
In a method set, each method must have a
<a href="#Uniqueness_of_identifiers">unique</a>
non-<a href="#Blank_identifier">blank</a> <a href="#MethodName">method name</a>.
</p>
<p>
The method set of a type determines the interfaces that the
type <a href="#Interface_types">implements</a>
and the methods that can be <a href="#Calls">called</a>
using a receiver of that type.
In a method set, each method must have a
<a href="#Uniqueness_of_identifiers">unique</a>
non-<a href="#Blank_identifier">blank</a> <a href="#MethodName">method name</a>.
</p>
<h3 id="Boolean_types">Boolean types</h3>
@ -1236,23 +1259,33 @@ func(n int) func(p *T)
<h3 id="Interface_types">Interface types</h3>
<p>
An interface type specifies a <a href="#Method_sets">method set</a> called its <i>interface</i>.
A variable of interface type can store a value of any type with a method set
that is any superset of the interface. Such a type is said to
<i>implement the interface</i>.
An interface type defines a <i>type set</i>.
A variable of interface type can store a value of any type that is in the type
set of the interface. Such a type is said to <i>implement the interface</i>.
The value of an uninitialized variable of interface type is <code>nil</code>.
</p>
<pre class="ebnf">
InterfaceType = "interface" "{" { ( MethodSpec | InterfaceTypeName ) ";" } "}" .
MethodSpec = MethodName Signature .
MethodName = identifier .
InterfaceTypeName = TypeName .
InterfaceType = "interface" "{" { InterfaceElem ";" } "}" .
InterfaceElem = MethodElem | TypeElem .
MethodElem = MethodName Signature .
MethodName = identifier .
TypeElem = TypeTerm { "|" TypeTerm } .
TypeTerm = [ "~" ] Type .
</pre>
<p>
An interface type may specify methods <i>explicitly</i> through method specifications,
or it may <i>embed</i> methods of other interfaces through interface type names.
An interface type is specified by a list of <i>interface elements</i>.
An interface element is either a method or a type element,
where a type element is a union of one or more type terms.
A type term is either a single type or a single underlying type.
</p>
<p>
In its most basic form an interface specifies a (possibly empty) list of methods.
The type set defined by such an interface is the set of types which implement all of
those methods, and the corresponding <a href="#Method_sets">method set</a> consists
exactly of the methods specified by the interface.
</p>
<pre>
@ -1297,15 +1330,19 @@ then the <code>File</code> interface is implemented by both <code>S1</code> and
</p>
<p>
A type implements any interface comprising any subset of its methods
and may therefore implement several distinct interfaces. For
instance, all types implement the <i>empty interface</i>:
Every type that is a member of the type set of an interface implements that interface.
Any given type may implement several distinct interfaces.
For instance, all types implement the <i>empty interface</i> which stands for the set of all types:
</p>
<pre>
interface{}
</pre>
<p>
For convenience, the predeclared type <code>any</code> is an alias for the empty interface.
</p>
<p>
Similarly, consider this interface specification,
which appears within a <a href="#Type_declarations">type declaration</a>
@ -1334,12 +1371,16 @@ as the <code>File</code> interface.
</p>
<p>
An interface <code>T</code> may use a (possibly qualified) interface type
name <code>E</code> in place of a method specification. This is called
In a slightly more general form
an interface <code>T</code> may use a (possibly qualified) interface type
name <code>E</code> as an interface element. This is called
<i>embedding</i> interface <code>E</code> in <code>T</code>.
The <a href="#Method_sets">method set</a> of <code>T</code> is the <i>union</i>
of the method sets of <code>T</code>s explicitly declared methods and of
<code>T</code>s embedded interfaces.
The type set of <code>T</code> is the <i>intersection</i> of the type sets
defined by <code>T</code>'s explicitly declared methods and the type sets
of <code>T</code>s embedded interfaces.
In other words, the type set of <code>T</code> is the set of all types that implement all the
explicitly declared methods of <code>T</code> and also all the methods of
<code>E</code>.
</p>
<pre>
@ -1361,8 +1402,7 @@ type ReadWriter interface {
</pre>
<p>
A <i>union</i> of method sets contains the (exported and non-exported)
methods of each method set exactly once, and methods with the
When embedding interfaces, methods with the
<a href="#Uniqueness_of_identifiers">same</a> names must
have <a href="#Type_identity">identical</a> signatures.
</p>
@ -1374,6 +1414,134 @@ type ReadCloser interface {
}
</pre>
<p>
Finally, in their most general form, an interface element may be an arbitrary type
<code>T</code>, a type term of the form <code>~T</code>, or a union of type terms
<code>T1 | T2 | … Tn</code>.
Together with method specifications, these elements enable the precise
definition of an interface's type set as follows:
</p>
<ul>
<li>The type set of the empty interface is the set of all types.
</li>
<li>The type set of a non-empty interface is the intersection of the type sets
of its interface elements.
</li>
<li>The type set of a method specification is the set of types
whose method sets include that method.
</li>
<li>The type set of a non-interface type is the set consisting
of just that type.
</li>
<li>The type set of a term of the form <code>~T</code>
is the set of types whose underlying type is <code>T</code>.
</li>
<li>The type set of a <i>union</i> of terms <code>T1 | T2 | … Tn</code>
is the union of the type sets of the terms.
</li>
</ul>
<pre>
// An interface representing only the type int.
interface {
int
}
// An interface representing all types with underlying type int.
interface {
~int
}
// An interface representing all types with underlying type int which implement the String method.
interface {
~int
String() string
}
// An interface representing an empty type set: there is no type that is both an int and a string.
interface {
int
string
}
</pre>
<p>
In a term of the form <code>~T</code>, the underlying type of <code>T</code>
must be itself, and <code>T</code> cannot be an interface.
</p>
<pre>
type MyInt int
interface {
~[]byte // the underlying type of []byte is itself
~MyInt // illegal: the underlying type of MyInt is not MyInt
~error // illegal: error is an interface
}
</pre>
<p>
Union expressions denote unions of type sets:
</p>
<pre>
// The Floats interface represents all floating-point types
// (including any named types whose underlying types are
// either float32 or float64).
type Floats interface {
~float32 | ~float64
}
</pre>
<p>
In a union expression, a term cannot be a type parameter, and the type sets of all
non-interface terms must be pairwise disjoint (the pairwise intersection of the type sets must be empty).
Given a type parameter <code>P</code>:
</p>
<pre>
interface {
P // illegal: the term P is a type parameter
int | P // illegal: the term P is a type parameter
~int | MyInt // illegal: the type sets for ~int and MyInt are not disjoint (~int includes MyInt)
float32 | Floats // overlapping type sets but Floats is an interface
}
</pre>
<p>
Implementation restriction:
A union expression with more than one term cannot contain interface types
with non-empty <a href="#Method_sets">method sets</a>.
</p>
<p>
Interfaces that contain union or tilde terms (not just methods) may only be used
as type constraints, or as elements of other interfaces used as constraints. They
cannot be the types of values or variables, or components of other, non-interface types.
</p>
<pre>
var x Floats // illegal: Floats is restricted by float32 and float64
var x interface{} = Floats(nil) // illegal
type Floatish struct {
f Floats // illegal
}
</pre>
<!-- TODO The rule below needs to be generalized to interface elements.
It should be factored out and generalized to other types
such as arrays and structs which are currently missing such a
rule. See also #5069.
-->
<p>
An interface type <code>T</code> may not embed itself
or any interface type that embeds <code>T</code>, recursively.
@ -1872,7 +2040,8 @@ The following identifiers are implicitly declared in the
</p>
<pre class="grammar">
Types:
bool byte complex64 complex128 error float32 float64
any bool byte comparable
complex64 complex128 error float32 float64
int int8 int16 int32 int64 rune string
uint uint8 uint16 uint32 uint64 uintptr