diff --git a/doc/go_spec.txt b/doc/go_spec.txt
index 0e969406ba44e6894ae6f61a70afccc02f88ec59..027b133dfacf7e629309bd400fd7bc28844268f0 100644
--- a/doc/go_spec.txt
+++ b/doc/go_spec.txt
@@ -4,7 +4,7 @@ The Go Programming Language Specification (DRAFT)
 Robert Griesemer, Rob Pike, Ken Thompson
 
 ----
-(November 4, 2008)
+(November 7, 2008)
 
 
 This document is a semi-formal specification of the Go systems
@@ -157,6 +157,7 @@ Contents
 		Channel types
 		Function types
 		Interface types
+		Type equality
 
 	Expressions
 		Operands
@@ -289,15 +290,15 @@ implementation, Go treats these as distinct characters.
 Characters
 ----
 
-In the grammar we use the notation
+In the grammar the term
 
 	utf8_char
 
-to refer to an arbitrary Unicode code point encoded in UTF-8. We use
+denotes an arbitrary Unicode code point encoded in UTF-8. Similarly,
 
 	non_ascii
 
-to refer to the subset of "utf8_char" code points with values >= 128.
+denotes the subset of "utf8_char" code points with values >= 128.
 
 
 Letters and digits
@@ -719,6 +720,7 @@ Type declarations
 ----
 
 A type declaration specifies a new type and binds an identifier to it.
+The identifier is called the ``type name''; it denotes the type.
 
 	TypeDecl = "type" Decl<TypeSpec> .
 	TypeSpec = identifier Type .
@@ -834,18 +836,24 @@ TODO: export as a mechanism for public and private struct fields?
 Types
 ----
 
-A type specifies the set of values that variables of that type may
-assume, and the operators that are applicable.
+A type specifies the set of values that variables of that type may assume
+and the operators that are applicable.
 
-There are basic types and composite types. Basic types are predeclared.
-Composite types are arrays, maps, channels, structures, functions, pointers,
-and interfaces. They are constructed from other (basic or composite) types.
+A type may be specified by a type name (§Type declarations)
+or a type literal.
 
-	Type =
-		TypeName | ArrayType | ChannelType | InterfaceType |
-		FunctionType | MapType | StructType | PointerType .
+	Type = TypeName | TypeLit .
 	TypeName = QualifiedIdent.
-	
+	TypeLit =
+		ArrayType | StructType | PointerType | FunctionType |
+		ChannelType | MapType | InterfaceType .
+
+There are basic types and composite types. Basic types are predeclared and
+denoted by their type names.
+Composite types are arrays, maps, channels, structures, functions, pointers,
+and interfaces. They are constructed from other (basic or composite) types
+and denoted by their type names or by type literals.
+
 Types may be ``complete'' or ''incomplete''. Basic, pointer, function and
 interface types are always complete (although their components, such
 as the base type of a pointer type, may be incomplete). All other types are
@@ -868,7 +876,7 @@ Need to resolve.
 
 The ``static type'' (or simply ``type'') of a variable is the type defined by
 the variable's declaration. The ``dynamic type'' of a variable is the actual
-type of the value stored in a variable at runtime. Except for variables of
+type of the value stored in a variable at run-time. Except for variables of
 interface type, the dynamic type of a variable is always its static type.
 
 Variables of interface type may hold values with different dynamic types
@@ -978,10 +986,6 @@ If the length is present in the declaration, the array is called
 	ArrayLength = Expression .
 	ElementType = CompleteType .
 
-Type equality: Two array types are equal only if both have the same element
-type and if both are either fixed arrays with the same array length, or both
-are open arrays.
-
 The length of an array "a" can be discovered using the built-in function
 
 	len(a)
@@ -1169,11 +1173,6 @@ This allows the construction of mutually recursive types such as:
 	type S1 struct { s2 *S2 }
 	type S2 struct { s1 *S1 }
 
-Type equality: Two struct types are equal only if both have the same number
-of fields in the same order, corresponding fields are either both named or
-anonymous, and the corresponding field types are equal. Specifically,
-field names don't have to match.
-
 Assignment compatibility: Structs are assignment compatible to variables of
 equal type only.
 
@@ -1201,9 +1200,6 @@ such as:
 	type S1 struct { s2 *S2 }
 	type S2 struct { s1 *S1 }
 
-Type equality: Two pointer types are equal only if both have equal
-base types.
-
 Assignment compatibility: A pointer is assignment compatible to a variable
 of pointer type, only if both types are equal.
 
@@ -1235,9 +1231,6 @@ Allocation: A map may only be used as a base type of a pointer type.
 There are no variables, parameters, array, struct, or map fields of
 map type, only of pointers to maps.
 
-Type equivalence: Two map types are equal only if both have equal
-key and value types.
-
 Assignment compatibility: A pointer to a map type is assignment
 compatible to a variable of pointer to map type only if both types
 are equal.
@@ -1251,17 +1244,18 @@ to synchronize execution and exchange values of a specified type. This
 type must be a complete type (§Types).
 
 Upon creation, a channel can be used both to send and to receive.
-By conversion or assignment, a 'full' channel may be constrained only to send or
-to receive. Such a restricted channel is called a 'send channel' or a 'receive channel'.
+By conversion or assignment, a channel may be constrained only to send or
+to receive. This constraint is called a channel's ``direction''; either
+bi-directional (unconstrained), send, or receive.
 
-	ChannelType = FullChannel | SendChannel | RecvChannel .
-	FullChannel = "chan" ValueType .
+	ChannelType = Channel | SendChannel | RecvChannel .
+	Channel = "chan" ValueType .
 	SendChannel = "chan" "<-" ValueType .
 	RecvChannel = "<-" "chan" ValueType .
 
-	chan T         // a channel that can exchange values of type T
-	chan <- float  // a channel that can only be used to send floats
-	<-chan int     // a channel that can receive only ints
+	chan T         // can send and receive values of type T
+	chan <- float  // can only be used to send floats
+	<-chan int     // can receive only ints
 
 Channel variables always have type pointer to channel.
 It is an error to attempt to use a channel value and in
@@ -1311,11 +1305,6 @@ In particular, v := func() {} creates a variable of type *(). To call the
 function referenced by v, one writes v(). It is illegal to dereference a
 function pointer.
 
-Type equality: Two function types are equal if both have the same number
-of parameters and result values and if corresponding parameter and result
-types are equal. In particular, the parameter and result names are ignored
-for the purpose of type equivalence.
-
 Assignment compatibility: A function pointer can be assigned to a function
 (pointer) variable only if both function types are equal.
 
@@ -1337,9 +1326,9 @@ the set of methods specified by the interface type, and the value "nil".
 		Close();
 	}
 
-Any type whose interface has, possibly as a subset, the complete
-set of methods of an interface I is said to implement interface I.
-For instance, if two types S1 and S2 have the methods
+Any type (including interface types) whose interface has, possibly as a
+subset, the complete set of methods of an interface I is said to implement
+interface I. For instance, if two types S1 and S2 have the methods
 
 	func (p T) Read(b Buffer) bool { return ... }
 	func (p T) Write(b Buffer) bool { return ... }
@@ -1354,14 +1343,14 @@ All types implement the empty interface:
 	interface {}
 
 In general, a type implements an arbitrary number of interfaces.
-For instance, if we have
+For instance, consider the interface
 
 	type Lock interface {
 		lock();
 		unlock();
 	}
 
-and S1 and S2 also implement
+If S1 and S2 also implement
 
 	func (p T) lock() { ... }
 	func (p T) unlock() { ... }
@@ -1381,14 +1370,120 @@ This allows the construction of mutually recursive types such as:
 		bar(T1) int;
 	}
 
-Type equivalence: Two interface types are equal only if both declare the same
-number of methods with the same names, and corresponding (by name) methods
-have the same function types.
-
 Assignment compatibility: A value can be assigned to an interface variable
 if the static type of the value implements the interface or if the value is "nil".
 
 
+Type equality
+----
+
+Types may be ``different'', ``structurally equal'', or ``identical''.
+Go is a type-safe language; generally different types cannot be mixed
+in binary operations, and values cannot be assigned to variables of different
+types. However, values may be assigned to variables of structually
+equal types. Finally, type guards succeed only if the dynamic type
+is identical to or implements the type tested against (§Type guards).
+
+Structural type equality (equality for short) is defined by these rules:
+
+Two type names denote equal types if the types in the corresponding declarations
+are equal. Two type literals specify equal types if they have the same
+literal structure and corresponding components have equal types. Loosely
+speaking, two types are equal if their values have the same layout in memory.
+More precisely:
+
+	- Two array types are equal if they have equal element types and if they
+	  are either fixed arrays with the same array length, or they are open
+	  arrays.
+
+	- Two struct types are equal if they have the same number of fields in the
+	  same order, corresponding fields are either both named or both anonymous,
+	  and corresponding field types are equal. Note that field names
+	  do not have to match.
+
+	- Two pointer types are equal if they have equal base types.
+
+	- Two function types are equal if they have the same number of parameters
+	  and result values and if corresponding parameter and result types are
+	  equal (a "..." parameter is equal to another "..." parameter).
+	  Note that parameter and result names do not have to match.
+
+	- Two channel types are equal if they have equal value types and
+	  the same direction.
+
+	- Two map types are equal if they have equal key and value types.
+
+	- Two interface types are equal if they have the same set of methods
+	  with the same names and equal function types. Note that the order
+	  of the methods in the respective type declarations is irrelevant.
+
+
+Type identity is defined by these rules:
+
+Two type names denote identical types if they originate in the same
+type declaration. Two type literals specify identical types if they have the
+same literal structure and corresponding components have identical types.
+More precisely:
+
+	- Two array types are identical if they have identical element types and if
+	  they are either fixed arrays with the same array length, or they are open
+	  arrays.
+
+	- Two struct types are identical if they have the same number of fields in
+	  the same order, corresponding fields either have both the same name or
+	  are both anonymous, and corresponding field types are identical.
+
+	- Two pointer types are identical if they have identical base types.
+
+	- Two function types are identical if they have the same number of
+	  parameters and result values both with the same (or absent) names, and
+	  if corresponding parameter and result types are identical (a "..."
+	  parameter is identical to another "..." parameter with the same name).
+
+	- Two channel types are identical if they have identical value types and
+	  the same direction.
+
+	- Two map types are identical if they have identical key and value types.
+
+	- Two interface types are identical if they have the same set of methods
+	  with the same names and identical function types. Note that the order
+	  of the methods in the respective type declarations is irrelevant.
+
+Note that the type denoted by a type name is identical only to the type literal
+in the type name's declaration.
+
+Finally, two types are different if they are not structurally equal.
+(By definition, they cannot be identical, either).
+
+For instance, given the declarations
+
+	type (
+		T0 []string;
+		T1 []string
+		T2 struct { a, b int };
+		T3 struct { a, c int };
+		T4 *(int, float) *T0
+		T5 *(x int, y float) *[]string
+	)
+
+these are some types that are equal
+
+	T0 and T0
+	T0 and []string
+	T2 and T3
+	T4 and T5
+	T3 and struct { a int; int }
+
+and these are some types that are identical
+
+	T0 and T0
+	[]int and []int
+	struct { a, b *T5 } and struct { a, b *T5 }
+
+As an example, "T0" and "T1" are equal but not identical because they have
+different declarations.
+
+
 Expressions
 ----
 
@@ -1511,7 +1606,7 @@ Given
 	type Rat struct { num, den int };
 	type Num struct { r Rat; f float; s string };
 
-we can write
+one can write
 
 	pi := Num{Rat{22, 7}, 3.14159, "pi"};
 
@@ -1576,7 +1671,7 @@ Primary expressions
 	Selector = "." identifier .
 	Index = "[" Expression "]" .
 	Slice = "[" Expression ":" Expression "]" .
-	TypeGuard = "." "(" QualifiedIdent ")" .
+	TypeGuard = "." "(" Type ")" .
 	Call = "(" [ ExpressionList ] ")" .
 
 
@@ -1660,7 +1755,7 @@ declarations:
 
 	var p *T2;  // with p != nil and p.T1 != nil
 
-we can write:
+one can write:
 
 	p.z         // (*p).z
 	p.y         // ((*p).T1).y
@@ -1734,7 +1829,41 @@ would have no effect on ``a''.
 Type guards
 ----
 
-TODO: write this section
+For an expression "x" and a type "T", the primary expression
+
+	x.(T)
+
+asserts that the value stored in "x" is an element of type "T" (§Types).
+The notation ".(T)" is called a ``type guard'', and "x.(T)" is called
+a ``guarded expression''. The type of "x" must be an interface type.
+
+More precisely, if "T" is not an interface type, the expression asserts
+that the dynamic type of "x" is identical to the type "T" (§Types).
+If "T" is an interface type, the expression asserts that the dynamic type
+of T implements the interface "T" (§Interface types). Because it can be
+verified statically, a type guard in which the static type of "x" implements
+the interface "T" is illegal. The type guard is said to succeed if the
+assertion holds.
+
+If the type guard succeeds, the value of the guarded expression is the value
+stored in "x" and its type is "T". If the type guard fails, a run-time
+exception occurs. In other words, even though the dynamic type of "x"
+is only known at run-time, the type of the guarded expression "x.(T)" is
+known to be "T" in a correct program.
+
+As a special form, if a guarded expression is used in an assignment
+
+	v, ok = x.(T)
+	v, ok := x.(T)
+
+the result of the guarded expression is a pair of values with types "(T, bool)".
+If the type guard succeeds, the expression returns the pair "(x.(T), true)";
+that is, the value stored in "x" (of type "T") is assigned to "v", and "ok"
+is set to true. If the type guard fails, the value in "v" is set to the initial
+value for the type of "v" (§Program initialization and execution), and "ok" is
+set to false. No run-time exception occurs in this case.
+
+TODO add examples
 
 
 Calls
@@ -1773,7 +1902,7 @@ TODO expand this section (right now only "..." parameters are covered).
 
 Inside a function, the type of the "..." parameter is the empty interface
 "interface {}". The dynamic type of the parameter - that is, the type of
-the actual value stored in the parameter - is of the form (in pseudo-
+the value stored in the parameter - is of the form (in pseudo-
 notation)
 
 	*struct {
@@ -1791,7 +1920,7 @@ Thus, arguments provided in place of a "..." parameter are wrapped into
 a corresponding struct, and a pointer to the struct is passed to the
 function instead of the actual arguments.
 
-For instance, given the function
+For instance, consider the function
 
 	func f(x int, s string, f_extra ...)
 
@@ -1802,7 +1931,7 @@ and the call
 Upon invocation, the parameters "3.14", "true", and "*[3]int{1, 2, 3}"
 are wrapped into a struct and the pointer to the struct is passed to f.
 In f the type of parameter "f_extra" is "interface{}".
-The dynamic type of "f_extra" is the type of the actual value assigned
+The dynamic type of "f_extra" is the type of the value assigned
 to it upon invocation (the field names "arg0", "arg1", "arg2" are made
 up for illustration only, they are not accessible via reflection):
 
@@ -1826,7 +1955,7 @@ as
 
 	g(x, f_extra);
 
-Inside g, the actual value stored in g_extra is the same as the value stored
+Inside g, the value stored in g_extra is the same as the value stored
 in f_extra.
 
 
@@ -2028,7 +2157,7 @@ pointer to function.  Consider the type T with method M:
 	func (tp *T) M(a int) int;
 	var t *T;
 
-To construct the address of method M, we write
+To construct the address of method M, one writes
 
 	&t.M
 
@@ -2187,12 +2316,6 @@ In all other cases a semicolon is required to separate two statements. Since the
 is an empty statement, a statement list can always be ``terminated'' with a semicolon.
 
 
-Label declarations
-----
-
-TODO write this section
-
-
 Empty statements
 ----
 
@@ -2584,14 +2707,14 @@ values:
 Break statements
 ----
 
-Within a for or switch statement, a break statement terminates execution of
-the innermost for or switch statement.
+Within a for, switch, or select statement, a break statement terminates
+execution of the innermost such statement.
 
 	BreakStat = "break" [ identifier ].
 
-If there is an identifier, it must be the label name of an enclosing
-for or switch
-statement, and that is the one whose execution terminates.
+If there is an identifier, it must be a label marking an enclosing
+for, switch, or select statement, and that is the one whose execution
+terminates.
 
 	L: for i < n {
 		switch i {
@@ -2611,13 +2734,15 @@ loop at the post statement.
 The optional identifier is analogous to that of a break statement.
 
 
-Label declaration
+Label declarations
 ----
 
 A label declaration serves as the target of a goto, break or continue statement.
 
 	LabelDecl = identifier ":" .
 
+Example:
+
 	Error:
 
 
@@ -2771,7 +2896,7 @@ yields a valid value; there is no signal for overflow.
 
 2) Between integer and floating point types, or between floating point
 types.  To avoid overdefining the properties of the conversion, for
-now we define it as a ``best effort'' conversion.  The conversion
+now it is defined as a ``best effort'' conversion.  The conversion
 always succeeds but the value may be a NaN or other problematic
 result.  TODO: clarify?
 
@@ -2801,7 +2926,8 @@ Allocation
 The built-in function "new()" takes a type "T", optionally followed by a
 type-specific list of expressions. It allocates memory for a variable
 of type "T" and returns a pointer of type "*T" to that variable. The
-memory is initialized as described in the section on initial values.
+memory is initialized as described in the section on initial values
+(§Program initialization and execution).
 
 	new(type [, optional list of expressions])
 
@@ -3095,7 +3221,7 @@ If a type defines all methods of an interface, it
 implements that interface and thus can be used where that interface is
 required.  Unless used through a variable of interface type, methods
 can always be statically bound (they are not ``virtual''), and incur no
-runtime overhead compared to an ordinary function.
+run-time overhead compared to an ordinary function.
 
 [OLD
 Interface types, building on structures with methods, provide
@@ -3112,7 +3238,7 @@ structures.  If a structure implements all methods of an interface, it
 implements that interface and thus can be used where that interface is
 required.  Unless used through a variable of interface type, methods
 can always be statically bound (they are not ``virtual''), and incur no
-runtime overhead compared to an ordinary function.
+run-time overhead compared to an ordinary function.
 END]
 
 Go has no explicit notion of classes, sub-classes, or inheritance.