[dev.typealias] all: merge go1.8.3 into dev.typealias

352996a381 (tag: go1.8.3) [release-branch.go1.8] go1.8.3
bb5055d6f1 [release-branch.go1.8] doc: document go1.8.3
439c0c8be8 [release-branch.go1.8] cmd/compile: don't move spills to loop exits where the spill is dead
e396667ba3 [release-branch.go1.8] cmd/compile: zero ambiguously live variables at VARKILLs
daf6706f37 [release-branch.go1.8] runtime: use pselect6 for usleep on linux/386
958c64bbab [release-branch.go1.8] runtime: use pselect6 for usleep on linux/amd64 and linux/arm
195e20a976 [release-branch.go1.8] cmd/compile: ignore types when considering tuple select for CSE
f55bc1c4eb [release-branch.go1.8] net/http: update bundled http2 for gracefulShutdownCh lock contention slowdown
51f508bb4a [release-branch.go1.8] cmd/compile: fix s390x unsigned comparison constant merging rules
243dee1737 [release-branch.go1.8] cmd/go: if we get a C compiler dwarf2 warning, try without -g
a43c0d2dc8 [release-branch.go1.8] runtime: don't corrupt arena bounds on low mmap
1054085dcf [release-branch.go1.8] cmd/compile: fix store chain in schedule pass
18a13d373a [release-branch.go1.8] runtime: doubly fix "double wakeup" panic
6efa2f22ac [release-branch.go1.8] database/sql: ensure releaseConn is defined before a possible close
fb9770f09b [release-branch.go1.8] runtime: print debug info on "base out of range"
b6a8fc8d8c [release-branch.go1.8] doc: remove mentions of yacc tool
59870f9e19 (tag: go1.8.2) [release-branch.go1.8] go1.8.2
c9688ddb6b [release-branch.go1.8] doc: document go1.8.2 and go1.7.6
38d35f49e7 [release-branch.go1.8] crypto/elliptic: fix carry bug in x86-64 P-256 implementation.

Change-Id: I2aa0eab7a990d24e25809fb13ce6cb031104f474
diff --git a/VERSION b/VERSION
index 3e144cd..7b93113 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-go1.8.3
\ No newline at end of file
+go1.8.3.typealias
\ No newline at end of file
diff --git a/doc/go_spec.html b/doc/go_spec.html
index 5872eef..c71126d 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,6 +1,6 @@
 <!--{
 	"Title": "The Go Programming Language Specification",
-	"Subtitle": "Version of November 18, 2016",
+	"Subtitle": "Version of January 31, 2017",
 	"Path": "/ref/spec"
 }-->
 
@@ -738,7 +738,7 @@
 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 anonymous fields, as described
+Further rules apply 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
@@ -947,16 +947,16 @@
 <p>
 A struct is a sequence of named elements, called fields, each of which has a
 name and a type. Field names may be specified explicitly (IdentifierList) or
-implicitly (AnonymousField).
+implicitly (EmbeddedField).
 Within a struct, non-<a href="#Blank_identifier">blank</a> field names must
 be <a href="#Uniqueness_of_identifiers">unique</a>.
 </p>
 
 <pre class="ebnf">
-StructType     = "struct" "{" { FieldDecl ";" } "}" .
-FieldDecl      = (IdentifierList Type | AnonymousField) [ Tag ] .
-AnonymousField = [ "*" ] TypeName .
-Tag            = string_lit .
+StructType    = "struct" "{" { FieldDecl ";" } "}" .
+FieldDecl     = (IdentifierList Type | EmbeddedField) [ Tag ] .
+EmbeddedField = [ "*" ] TypeName .
+Tag           = string_lit .
 </pre>
 
 <pre>
@@ -974,16 +974,15 @@
 </pre>
 
 <p>
-A field declared with a type but no explicit field name is an <i>anonymous field</i>,
-also called an <i>embedded</i> field or an embedding of the type in the struct.
-An embedded type must be specified as
+A field declared with a type but no explicit field name is called an <i>embedded field</i>.
+An embedded field must be specified as
 a type name <code>T</code> or as a pointer to a non-interface type name <code>*T</code>,
 and <code>T</code> itself may not be
 a pointer type. The unqualified type name acts as the field name.
 </p>
 
 <pre>
-// A struct with four anonymous fields of type T1, *T2, P.T3 and *P.T4
+// A struct with four embedded fields of types T1, *T2, P.T3 and *P.T4
 struct {
 	T1        // field name is T1
 	*T2       // field name is T2
@@ -1000,15 +999,15 @@
 
 <pre>
 struct {
-	T     // conflicts with anonymous field *T and *P.T
-	*T    // conflicts with anonymous field T and *P.T
-	*P.T  // conflicts with anonymous field T and *T
+	T     // conflicts with embedded field *T and *P.T
+	*T    // conflicts with embedded field T and *P.T
+	*P.T  // conflicts with embedded field T and *T
 }
 </pre>
 
 <p>
 A field or <a href="#Method_declarations">method</a> <code>f</code> of an
-anonymous field in a struct <code>x</code> is called <i>promoted</i> if
+embedded field in a struct <code>x</code> is called <i>promoted</i> if
 <code>x.f</code> is a legal <a href="#Selectors">selector</a> that denotes
 that field or method <code>f</code>.
 </p>
@@ -1025,7 +1024,7 @@
 </p>
 <ul>
 	<li>
-	If <code>S</code> contains an anonymous field <code>T</code>,
+	If <code>S</code> contains an embedded field <code>T</code>,
 	the <a href="#Method_sets">method sets</a> of <code>S</code>
 	and <code>*S</code> both include promoted methods with receiver
 	<code>T</code>. The method set of <code>*S</code> also
@@ -1033,7 +1032,7 @@
 	</li>
 
 	<li>
-	If <code>S</code> contains an anonymous field <code>*T</code>,
+	If <code>S</code> contains an embedded field <code>*T</code>,
 	the method sets of <code>S</code> and <code>*S</code> both
 	include promoted methods with receiver <code>T</code> or
 	<code>*T</code>.
@@ -1434,8 +1433,8 @@
 	<li>Two struct types are identical if they have the same sequence of fields,
 	    and if corresponding fields have the same names, and identical types,
 	    and identical tags.
-	    Two anonymous fields are considered to have the same name. Lower-case field
-	    names from different packages are always different.</li>
+	    <a href="#Exported_identifiers">Non-exported</a> field names from different
+	    packages are always different.</li>
 
 	<li>Two pointer types are identical if they have identical base types.</li>
 
@@ -1445,8 +1444,9 @@
 	    Parameter and result names are not required to match.</li>
 
 	<li>Two interface types are identical if they have the same set of methods
-	    with the same names and identical function types. Lower-case method names from
-	    different packages are always different. The order of the methods is irrelevant.</li>
+	    with the same names and identical function types.
+	    <a href="#Exported_identifiers">Non-exported</a> method names from different
+	    packages are always different. The order of the methods is irrelevant.</li>
 
 	<li>Two map types are identical if they have identical key and value types.</li>
 
@@ -1891,7 +1891,7 @@
 type PtrMutex *Mutex
 
 // The method set of *PrintableMutex contains the methods
-// Lock and Unlock bound to its anonymous field Mutex.
+// Lock and Unlock bound to its embedded field Mutex.
 type PrintableMutex struct {
 	Mutex
 }
@@ -2492,13 +2492,13 @@
 A selector <code>f</code> may denote a field or method <code>f</code> of
 a type <code>T</code>, or it may refer
 to a field or method <code>f</code> of a nested
-<a href="#Struct_types">anonymous field</a> of <code>T</code>.
-The number of anonymous fields traversed
+<a href="#Struct_types">embedded field</a> of <code>T</code>.
+The number of embedded fields traversed
 to reach <code>f</code> is called its <i>depth</i> in <code>T</code>.
 The depth of a field or method <code>f</code>
 declared in <code>T</code> is zero.
 The depth of a field or method <code>f</code> declared in
-an anonymous field <code>A</code> in <code>T</code> is the
+an embedded field <code>A</code> in <code>T</code> is the
 depth of <code>f</code> in <code>A</code> plus one.
 </p>
 
diff --git a/src/cmd/compile/internal/gc/align.go b/src/cmd/compile/internal/gc/align.go
index eee801f..1dd04e3 100644
--- a/src/cmd/compile/internal/gc/align.go
+++ b/src/cmd/compile/internal/gc/align.go
@@ -74,7 +74,13 @@
 			lastzero = o
 		}
 		o += w
-		if o >= Thearch.MAXWIDTH {
+		maxwidth := Thearch.MAXWIDTH
+		// On 32-bit systems, reflect tables impose an additional constraint
+		// that each field start offset must fit in 31 bits.
+		if maxwidth < 1<<32 {
+			maxwidth = 1<<31 - 1
+		}
+		if o >= maxwidth {
 			yyerror("type %L too large", errtype)
 			o = 8 // small but nonzero
 		}
diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go
index ffc5419..5f14e01 100644
--- a/src/cmd/compile/internal/gc/bexport.go
+++ b/src/cmd/compile/internal/gc/bexport.go
@@ -140,11 +140,12 @@
 const forceObjFileStability = true
 
 // Current export format version. Increase with each format change.
-// 3: added aliasTag and export of aliases
-// 2: removed unused bool in ODCL export
+// 4: type name objects support type aliases, uses aliasTag
+// 3: Go1.8 encoding (same as version 2, aliasTag defined but never used)
+// 2: removed unused bool in ODCL export (compiler only)
 // 1: header format change (more regular), export package for _ struct fields
 // 0: Go1.7 encoding
-const exportVersion = 3
+const exportVersion = 4
 
 // exportInlined enables the export of inlined function bodies and related
 // dependencies. The compiler should work w/o any loss of functionality with
@@ -351,8 +352,8 @@
 			p.tracef("\n")
 		}
 
-		if sym.Flags&SymAlias != 0 {
-			Fatalf("exporter: unexpected alias %v in inlined function body", sym)
+		if sym.isAlias() {
+			Fatalf("exporter: unexpected type alias %v in inlined function body", sym)
 		}
 
 		p.obj(sym)
@@ -446,30 +447,6 @@
 }
 
 func (p *exporter) obj(sym *Sym) {
-	if sym.Flags&SymAlias != 0 {
-		p.tag(aliasTag)
-		p.pos(nil) // TODO(gri) fix position information
-		// Aliases can only be exported from the package that
-		// declares them (aliases to aliases are resolved to the
-		// original object, and so are uses of aliases in inlined
-		// exported function bodies). Thus, we only need the alias
-		// name without package qualification.
-		if sym.Pkg != localpkg {
-			Fatalf("exporter: export of non-local alias: %v", sym)
-		}
-		p.string(sym.Name)
-		orig := sym.Def.Sym
-		if orig.Flags&SymAlias != 0 {
-			Fatalf("exporter: original object %v marked as alias", sym)
-		}
-		p.qualifiedName(orig)
-		return
-	}
-
-	if sym != sym.Def.Sym {
-		Fatalf("exporter: exported object %v is not original %v", sym, sym.Def.Sym)
-	}
-
 	// Exported objects may be from different packages because they
 	// may be re-exported via an exported alias or as dependencies in
 	// exported inlined function bodies. Thus, exported object names
@@ -509,7 +486,13 @@
 			Fatalf("exporter: export of incomplete type %v", sym)
 		}
 
-		p.tag(typeTag)
+		if sym.isAlias() {
+			p.tag(aliasTag)
+			p.pos(n)
+			p.qualifiedName(sym)
+		} else {
+			p.tag(typeTag)
+		}
 		p.typ(t)
 
 	case ONAME:
@@ -868,19 +851,29 @@
 
 func (p *exporter) method(m *Field) {
 	p.pos(m.Nname)
-	p.fieldName(m)
+	p.methodName(m.Sym)
 	p.paramList(m.Type.Params(), false)
 	p.paramList(m.Type.Results(), false)
 }
 
-// fieldName is like qualifiedName but it doesn't record the package for exported names.
 func (p *exporter) fieldName(t *Field) {
 	name := t.Sym.Name
 	if t.Embedded != 0 {
-		name = "" // anonymous field
-		if bname := basetypeName(t.Type); bname != "" && !exportname(bname) {
-			// anonymous field with unexported base type name
-			name = "?" // unexported name to force export of package
+		// anonymous field - we distinguish between 3 cases:
+		// 1) field name matches base type name and is exported
+		// 2) field name matches base type name and is not exported
+		// 3) field name doesn't match base type name (alias name)
+		bname := basetypeName(t.Type)
+		if name == bname {
+			if exportname(name) {
+				name = "" // 1) we don't need to know the field name or package
+			} else {
+				name = "?" // 2) use unexported name "?" to force package export
+			}
+		} else {
+			// 3) indicate alias and export name as is
+			// (this requires an extra "@" but this is a rare case)
+			p.string("@")
 		}
 	}
 	p.string(name)
@@ -889,16 +882,23 @@
 	}
 }
 
+// methodName is like qualifiedName but it doesn't record the package for exported names.
+func (p *exporter) methodName(sym *Sym) {
+	p.string(sym.Name)
+	if !exportname(sym.Name) {
+		p.pkg(sym.Pkg)
+	}
+}
+
 func basetypeName(t *Type) string {
 	s := t.Sym
 	if s == nil && t.IsPtr() {
 		s = t.Elem().Sym // deref
 	}
-	// s should exist, but be conservative
 	if s != nil {
 		return s.Name
 	}
-	return ""
+	return "" // unnamed type
 }
 
 func (p *exporter) paramList(params *Type, numbered bool) {
@@ -1797,7 +1797,7 @@
 	nilTag
 	unknownTag // not used by gc (only appears in packages with errors)
 
-	// Aliases
+	// Type aliases
 	aliasTag
 )
 
@@ -1835,7 +1835,7 @@
 	-nilTag:      "nil",
 	-unknownTag:  "unknown",
 
-	// Aliases
+	// Type aliases
 	-aliasTag: "alias",
 }
 
@@ -1889,7 +1889,7 @@
 			Types[TCOMPLEX128],
 			Types[TSTRING],
 
-			// aliases
+			// basic type aliases
 			bytetype,
 			runetype,
 
diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go
index 94c1184..752f65b 100644
--- a/src/cmd/compile/internal/gc/bimport.go
+++ b/src/cmd/compile/internal/gc/bimport.go
@@ -86,10 +86,10 @@
 
 	// read version specific flags - extend as necessary
 	switch p.version {
-	// case 4:
+	// case 5:
 	// 	...
 	//	fallthrough
-	case 3, 2, 1:
+	case 4, 3, 2, 1:
 		p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
 		p.trackAllTypes = p.bool()
 		p.posInfoFormat = p.bool()
@@ -317,6 +317,12 @@
 		val := p.value(typ)
 		importconst(sym, idealType(typ), nodlit(val))
 
+	case aliasTag:
+		p.pos()
+		sym := p.qualifiedName()
+		typ := p.typ()
+		importalias(sym, typ)
+
 	case typeTag:
 		p.typ()
 
@@ -356,17 +362,6 @@
 			}
 		}
 
-	case aliasTag:
-		p.pos()
-		alias := importpkg.Lookup(p.string())
-		orig := p.qualifiedName()
-
-		// Although the protocol allows the alias to precede the original,
-		// this never happens in files produced by gc.
-		alias.Flags |= SymAlias
-		alias.Def = orig.Def
-		importsym(alias, orig.Def.Op)
-
 	default:
 		formatErrorf("unexpected object (tag = %d)", tag)
 	}
@@ -473,14 +468,7 @@
 			result := p.paramList()
 			nointerface := p.bool()
 
-			base := recv[0].Type
-			star := false
-			if base.IsPtr() {
-				base = base.Elem()
-				star = true
-			}
-
-			n := methodname0(sym, star, base.Sym)
+			n := newfuncname(methodname(sym, recv[0].Type))
 			n.Type = functypefield(recv[0], params, result)
 			checkwidth(n.Type)
 			addmethod(sym, n.Type, false, nointerface)
@@ -583,19 +571,22 @@
 
 func (p *importer) field() *Field {
 	p.pos()
-	sym := p.fieldName()
+	sym, alias := p.fieldName()
 	typ := p.typ()
 	note := p.string()
 
 	f := newField()
 	if sym.Name == "" {
-		// anonymous field - typ must be T or *T and T must be a type name
+		// anonymous field: typ must be T or *T and T must be a type name
 		s := typ.Sym
 		if s == nil && typ.IsPtr() {
 			s = typ.Elem().Sym // deref
 		}
 		sym = sym.Pkg.Lookup(s.Name)
 		f.Embedded = 1
+	} else if alias {
+		// anonymous field: we have an explicit name because it's a type alias
+		f.Embedded = 1
 	}
 
 	f.Sym = sym
@@ -618,7 +609,7 @@
 
 func (p *importer) method() *Field {
 	p.pos()
-	sym := p.fieldName()
+	sym := p.methodName()
 	params := p.paramList()
 	result := p.paramList()
 
@@ -629,18 +620,44 @@
 	return f
 }
 
-func (p *importer) fieldName() *Sym {
+func (p *importer) fieldName() (*Sym, bool) {
 	name := p.string()
 	if p.version == 0 && name == "_" {
-		// version 0 didn't export a package for _ fields
+		// version 0 didn't export a package for _ field names
+		// but used the builtin package instead
+		return builtinpkg.Lookup(name), false
+	}
+	pkg := localpkg
+	alias := false
+	switch name {
+	case "":
+		// 1) field name matches base type name and is exported: nothing to do
+	case "?":
+		// 2) field name matches base type name and is not exported: need package
+		name = ""
+		pkg = p.pkg()
+	case "@":
+		// 3) field name doesn't match base type name (alias name): need name and possibly package
+		name = p.string()
+		alias = true
+		fallthrough
+	default:
+		if !exportname(name) {
+			pkg = p.pkg()
+		}
+	}
+	return pkg.Lookup(name), alias
+}
+
+func (p *importer) methodName() *Sym {
+	name := p.string()
+	if p.version == 0 && name == "_" {
+		// version 0 didn't export a package for _ method names
 		// but used the builtin package instead
 		return builtinpkg.Lookup(name)
 	}
 	pkg := localpkg
-	if name != "" && !exportname(name) {
-		if name == "?" {
-			name = ""
-		}
+	if !exportname(name) {
 		pkg = p.pkg()
 	}
 	return pkg.Lookup(name)
diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go
index 3cdd71d..856a7fa 100644
--- a/src/cmd/compile/internal/gc/dcl.go
+++ b/src/cmd/compile/internal/gc/dcl.go
@@ -519,10 +519,6 @@
 		Fatalf("funchdr: dclcontext = %d", dclcontext)
 	}
 
-	if Ctxt.Flag_dynlink && importpkg == nil && n.Func.Nname != nil {
-		makefuncsym(n.Func.Nname.Sym)
-	}
-
 	dclcontext = PAUTO
 	funcstart(n)
 
@@ -695,10 +691,20 @@
 
 // node n, which was returned by typedcl0
 // is being declared to have uncompiled type t.
-// return the ODCLTYPE node to use.
-func typedcl1(n *Node, t *Node, local bool) *Node {
-	n.Name.Param.Ntype = t
-	n.Local = local
+// returns the ODCLTYPE node to use.
+func typedcl1(n *Node, t *Node, pragma Pragma, alias bool) *Node {
+	if pragma != 0 && alias {
+		yyerror("cannot specify directive with type alias")
+		pragma = 0
+	}
+
+	n.Local = true
+
+	p := n.Name.Param
+	p.Ntype = t
+	p.Pragma = pragma
+	p.Alias = alias
+
 	return nod(ODCLTYPE, n, nil)
 }
 
@@ -1153,19 +1159,19 @@
 	return nil
 }
 
-func methodname(n *Node, t *Node) *Node {
+// methodname is a misnomer because this now returns a Sym, rather
+// than an ONAME.
+// TODO(mdempsky): Reconcile with methodsym.
+func methodname(s *Sym, recv *Type) *Sym {
 	star := false
-	if t.Op == OIND {
+	if recv.IsPtr() {
 		star = true
-		t = t.Left
+		recv = recv.Elem()
 	}
 
-	return methodname0(n.Sym, star, t.Sym)
-}
-
-func methodname0(s *Sym, star bool, tsym *Sym) *Node {
+	tsym := recv.Sym
 	if tsym == nil || isblanksym(s) {
-		return newfuncname(s)
+		return s
 	}
 
 	var p string
@@ -1181,14 +1187,13 @@
 		s = Pkglookup(p, tsym.Pkg)
 	}
 
-	return newfuncname(s)
+	return s
 }
 
 // Add a method, declared as a function.
 // - msym is the method symbol
 // - t is function type (with receiver)
 func addmethod(msym *Sym, t *Type, local, nointerface bool) {
-	// get field sym
 	if msym == nil {
 		Fatalf("no method symbol")
 	}
@@ -1309,7 +1314,7 @@
 	s1 := Pkglookup(s.Name+"·f", s.Pkg)
 	if !Ctxt.Flag_dynlink && s1.Def == nil {
 		s1.Def = newfuncname(s1)
-		s1.Def.Func.Shortname = newname(s)
+		s1.Def.Func.Shortname = s
 		funcsyms = append(funcsyms, s1.Def)
 	}
 	s.Fsym = s1
@@ -1326,8 +1331,11 @@
 		return
 	}
 	s1 := funcsym(s)
+	if s1.Def != nil {
+		return
+	}
 	s1.Def = newfuncname(s1)
-	s1.Def.Func.Shortname = newname(s)
+	s1.Def.Func.Shortname = s
 	funcsyms = append(funcsyms, s1.Def)
 }
 
diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go
index b4c15e4..58b2bf8 100644
--- a/src/cmd/compile/internal/gc/export.go
+++ b/src/cmd/compile/internal/gc/export.go
@@ -45,8 +45,8 @@
 		fmt.Printf("export symbol %v\n", n.Sym)
 	}
 
-	// Ensure original object is on exportlist before aliases.
-	if n.Sym.Flags&SymAlias != 0 {
+	// Ensure original types are on exportlist before type aliases.
+	if n.Sym.isAlias() {
 		exportlist = append(exportlist, n.Sym.Def)
 	}
 
@@ -83,7 +83,7 @@
 	if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN {
 		return
 	}
-	if n.Name.Param != nil && n.Name.Param.Ntype != nil && n.Name.Param.Ntype.Op == OTFUNC && n.Name.Param.Ntype.Left != nil { // method
+	if n.Type != nil && n.Type.IsKind(TFUNC) && n.Type.Recv() != nil { // method
 		return
 	}
 
@@ -348,6 +348,27 @@
 	}
 }
 
+// importalias declares symbol s as an imported type alias with type t.
+func importalias(s *Sym, t *Type) {
+	importsym(s, OTYPE)
+	if s.Def != nil && s.Def.Op == OTYPE {
+		if eqtype(t, s.Def.Type) {
+			return
+		}
+		yyerror("inconsistent definition for type alias %v during import\n\t%v (in %q)\n\t%v (in %q)", s, s.Def.Type, s.Importdef.Path, t, importpkg.Path)
+	}
+
+	n := newname(s)
+	n.Op = OTYPE
+	s.Importdef = importpkg
+	n.Type = t
+	declare(n, PEXTERN)
+
+	if Debug['E'] != 0 {
+		fmt.Printf("import type %v = %L\n", s, t)
+	}
+}
+
 func dumpasmhdr() {
 	b, err := bio.Create(asmhdr)
 	if err != nil {
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
index fffce44..16a4e34 100644
--- a/src/cmd/compile/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -1077,6 +1077,7 @@
 	OSEND:         3,
 	OANDAND:       2,
 	OOROR:         1,
+
 	// Statements handled by stmtfmt
 	OAS:         -1,
 	OAS2:        -1,
@@ -1104,7 +1105,8 @@
 	OSWITCH:     -1,
 	OXCASE:      -1,
 	OXFALL:      -1,
-	OEND:        0,
+
+	OEND: 0,
 }
 
 func (n *Node) exprfmt(s fmt.State, prec int) {
diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go
index a529ca4..63d6b41 100644
--- a/src/cmd/compile/internal/gc/go.go
+++ b/src/cmd/compile/internal/gc/go.go
@@ -63,9 +63,12 @@
 	SymSiggen
 	SymAsm
 	SymAlgGen
-	SymAlias // alias, original is Sym.Def.Sym
 )
 
+func (sym *Sym) isAlias() bool {
+	return sym.Def != nil && sym.Def.Sym != sym
+}
+
 // The Class of a variable/function describes the "storage class"
 // of a variable or function. During parsing, storage classes are
 // called declaration contexts.
@@ -87,7 +90,7 @@
 // of the compilers arrays.
 //
 // typedef	struct
-// {					// must not move anything
+// {				// must not move anything
 // 	uchar	array[8];	// pointer to data
 // 	uchar	nel[4];		// number of elements
 // 	uchar	cap[4];		// allocated number of elements
@@ -104,7 +107,7 @@
 // of the compilers strings.
 //
 // typedef	struct
-// {					// must not move anything
+// {				// must not move anything
 // 	uchar	array[8];	// pointer to data
 // 	uchar	nel[4];		// number of elements
 // } String;
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 1690944..f5fb72b 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -340,13 +340,16 @@
 	// Phase 1: const, type, and names and types of funcs.
 	//   This will gather all the information about types
 	//   and methods but doesn't depend on any of it.
+	//   We also defer type alias declarations until phase 2
+	//   to avoid cycles like #18640.
 	defercheckwidth()
 
 	// Don't use range--typecheck can add closures to xtop.
 	timings.Start("fe", "typecheck", "top1")
 	for i := 0; i < len(xtop); i++ {
-		if xtop[i].Op != ODCL && xtop[i].Op != OAS && xtop[i].Op != OAS2 {
-			xtop[i] = typecheck(xtop[i], Etop)
+		n := xtop[i]
+		if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias) {
+			xtop[i] = typecheck(n, Etop)
 		}
 	}
 
@@ -356,8 +359,9 @@
 	// Don't use range--typecheck can add closures to xtop.
 	timings.Start("fe", "typecheck", "top2")
 	for i := 0; i < len(xtop); i++ {
-		if xtop[i].Op == ODCL || xtop[i].Op == OAS || xtop[i].Op == OAS2 {
-			xtop[i] = typecheck(xtop[i], Etop)
+		n := xtop[i]
+		if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias {
+			xtop[i] = typecheck(n, Etop)
 		}
 	}
 	resumecheckwidth()
@@ -367,8 +371,9 @@
 	timings.Start("fe", "typecheck", "func")
 	var fcount int64
 	for i := 0; i < len(xtop); i++ {
-		if xtop[i].Op == ODCLFUNC || xtop[i].Op == OCLOSURE {
-			Curfn = xtop[i]
+		n := xtop[i]
+		if op := n.Op; op == ODCLFUNC || op == OCLOSURE {
+			Curfn = n
 			decldepth = 1
 			saveerrors()
 			typecheckslice(Curfn.Nbody.Slice(), Etop)
@@ -460,8 +465,9 @@
 	timings.Start("be", "compilefuncs")
 	fcount = 0
 	for i := 0; i < len(xtop); i++ {
-		if xtop[i].Op == ODCLFUNC {
-			funccompile(xtop[i])
+		n := xtop[i]
+		if n.Op == ODCLFUNC {
+			funccompile(n)
 			fcount++
 		}
 	}
@@ -924,7 +930,7 @@
 				continue
 			}
 
-			if s.Def.Sym != s && s.Flags&SymAlias == 0 {
+			if s.isAlias() {
 				// throw away top-level name left over
 				// from previous import . "x"
 				if s.Def.Name != nil && s.Def.Name.Pack != nil && !s.Def.Name.Pack.Used && nsyntaxerrors == 0 {
diff --git a/src/cmd/compile/internal/gc/noder.go b/src/cmd/compile/internal/gc/noder.go
index ce18297..9dbe769 100644
--- a/src/cmd/compile/internal/gc/noder.go
+++ b/src/cmd/compile/internal/gc/noder.go
@@ -154,11 +154,7 @@
 
 func (p *noder) varDecl(decl *syntax.VarDecl) []*Node {
 	names := p.declNames(decl.NameList)
-
-	var typ *Node
-	if decl.Type != nil {
-		typ = p.typeExpr(decl.Type)
-	}
+	typ := p.typeExprOrNil(decl.Type)
 
 	var exprs []*Node
 	if decl.Values != nil {
@@ -171,11 +167,7 @@
 
 func (p *noder) constDecl(decl *syntax.ConstDecl) []*Node {
 	names := p.declNames(decl.NameList)
-
-	var typ *Node
-	if decl.Type != nil {
-		typ = p.typeExpr(decl.Type)
-	}
+	typ := p.typeExprOrNil(decl.Type)
 
 	var exprs []*Node
 	if decl.Values != nil {
@@ -187,14 +179,11 @@
 
 func (p *noder) typeDecl(decl *syntax.TypeDecl) *Node {
 	name := typedcl0(p.name(decl.Name))
-	name.Name.Param.Pragma = Pragma(decl.Pragma)
 
-	var typ *Node
-	if decl.Type != nil {
-		typ = p.typeExpr(decl.Type)
-	}
+	// decl.Type may be nil but in that case we got a syntax error during parsing
+	typ := p.typeExprOrNil(decl.Type)
 
-	return typedcl1(name, typ, true)
+	return typedcl1(name, typ, Pragma(decl.Pragma), decl.Alias)
 }
 
 func (p *noder) declNames(names []*syntax.Name) []*Node {
@@ -259,19 +248,19 @@
 				yyerror("func main must have no arguments and no return values")
 			}
 		}
-
-		f.Func.Nname = newfuncname(name)
 	} else {
-		// Receiver MethodName Signature
-
-		f.Func.Shortname = newfuncname(name)
-		f.Func.Nname = methodname(f.Func.Shortname, t.Left.Right)
+		f.Func.Shortname = name
+		name = nblank.Sym // filled in by typecheckfunc
 	}
 
+	f.Func.Nname = newfuncname(name)
 	f.Func.Nname.Name.Defn = f
 	f.Func.Nname.Name.Param.Ntype = t // TODO: check if nname already has an ntype
 
-	declare(f.Func.Nname, PFUNC)
+	if fun.Recv == nil {
+		declare(f.Func.Nname, PFUNC)
+	}
+
 	funchdr(f)
 	return f
 }
@@ -467,6 +456,13 @@
 	return p.expr(typ)
 }
 
+func (p *noder) typeExprOrNil(typ syntax.Expr) *Node {
+	if typ != nil {
+		return p.expr(typ)
+	}
+	return nil
+}
+
 func (p *noder) chanDir(dir syntax.ChanDir) ChanDir {
 	switch dir {
 	case 0:
diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go
index 08ed560..6d5f2aa 100644
--- a/src/cmd/compile/internal/gc/obj.go
+++ b/src/cmd/compile/internal/gc/obj.go
@@ -213,7 +213,7 @@
 	}
 
 	for _, n := range funcsyms {
-		dsymptr(n.Sym, 0, n.Sym.Def.Func.Shortname.Sym, 0)
+		dsymptr(n.Sym, 0, n.Sym.Def.Func.Shortname, 0)
 		ggloblsym(n.Sym, int32(Widthptr), obj.DUPOK|obj.RODATA)
 	}
 
diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go
index 61ac67c..7cd0274 100644
--- a/src/cmd/compile/internal/gc/reflect.go
+++ b/src/cmd/compile/internal/gc/reflect.go
@@ -511,7 +511,7 @@
 // dnameField dumps a reflect.name for a struct field.
 func dnameField(s *Sym, ot int, spkg *Pkg, ft *Field) int {
 	var name string
-	if ft.Sym != nil && ft.Embedded == 0 {
+	if ft.Sym != nil {
 		name = ft.Sym.Name
 	}
 	isExported, fpkg := isExportedField(ft)
@@ -1345,7 +1345,14 @@
 			// ../../../../runtime/type.go:/structField
 			ot = dnameField(s, ot, pkg, f)
 			ot = dsymptr(s, ot, dtypesym(f.Type), 0)
-			ot = duintptr(s, ot, uint64(f.Offset))
+			offsetAnon := uint64(f.Offset) << 1
+			if offsetAnon>>1 != uint64(f.Offset) {
+				Fatalf("%v: bad field offset for %s", t, f.Sym.Name)
+			}
+			if f.Embedded != 0 {
+				offsetAnon |= 1
+			}
+			ot = duintptr(s, ot, offsetAnon)
 		}
 	}
 
diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go
index 8848bb5..0bd877e 100644
--- a/src/cmd/compile/internal/gc/syntax.go
+++ b/src/cmd/compile/internal/gc/syntax.go
@@ -27,7 +27,7 @@
 	// func
 	Func *Func
 
-	// ONAME
+	// ONAME, OTYPE, OPACK, OLABEL, some OLITERAL
 	Name *Name
 
 	Sym *Sym        // various
@@ -59,8 +59,8 @@
 	Noescape  bool  // func arguments do not escape; TODO(rsc): move Noescape to Func struct (see CL 7360)
 	Walkdef   uint8 // tracks state during typecheckdef; 2 == loop detected
 	Typecheck uint8 // tracks state during typechecking; 2 == loop detected
-	Local     bool
-	IsStatic  bool // whether this Node will be converted to purely static data
+	Local     bool  // type created in this file (see also Type.Local); TODO(gri): move this into flags
+	IsStatic  bool  // whether this Node will be converted to purely static data
 	Initorder uint8
 	Used      bool // for variable/label declared and not used error
 	Isddd     bool // is the argument variadic
@@ -180,14 +180,14 @@
 	n.Xoffset = x
 }
 
-// Name holds Node fields used only by named nodes (ONAME, OPACK, OLABEL, some OLITERAL).
+// Name holds Node fields used only by named nodes (ONAME, OTYPE, OPACK, OLABEL, some OLITERAL).
 type Name struct {
 	Pack      *Node  // real package for import . names
 	Pkg       *Pkg   // pkg for OPACK nodes
 	Heapaddr  *Node  // temp holding heap address of param (could move to Param?)
 	Defn      *Node  // initializing assignment
 	Curfn     *Node  // function for local variables
-	Param     *Param // additional fields for ONAME
+	Param     *Param // additional fields for ONAME, OTYPE
 	Decldepth int32  // declaration loop depth, increased for every loop or label
 	Vargen    int32  // unique name for ONAME within a function.  Function outputs are numbered starting at one.
 	Funcdepth int32
@@ -280,15 +280,16 @@
 	Innermost *Node
 	Outer     *Node
 
-	// OTYPE pragmas
+	// OTYPE
 	//
 	// TODO: Should Func pragmas also be stored on the Name?
 	Pragma Pragma
+	Alias  bool // node is alias for Ntype (only used when type-checking ODCLTYPE)
 }
 
 // Func holds Node fields used only with function-like nodes.
 type Func struct {
-	Shortname  *Node
+	Shortname  *Sym
 	Enter      Nodes // for example, allocate and initialize memory for escaping parameters
 	Exit       Nodes
 	Cvars      Nodes   // closure params
@@ -382,7 +383,7 @@
 	ODCLFUNC  // func f() or func (r) f()
 	ODCLFIELD // struct field, interface field, or func/method argument/return value.
 	ODCLCONST // const pi = 3.14
-	ODCLTYPE  // type Int int
+	ODCLTYPE  // type Int int or type Int = int
 
 	ODELETE    // delete(Left, Right)
 	ODOT       // Left.Sym (Left is of struct type)
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index 7cfd951..d5aa0a8 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -96,16 +96,16 @@
 	return fmt.Sprintf("etype=%d", et)
 }
 
-// sprint_depchain prints a dependency chain of nodes into fmt.
+// sprint_depchain prints a dependency chain of nodes into trace.
 // It is used by typecheck in the case of OLITERAL nodes
 // to print constant definition loops.
-func sprint_depchain(fmt_ *string, stack []*Node, cur *Node, first *Node) {
+func sprint_depchain(trace *string, stack []*Node, cur *Node, first *Node) {
 	for i := len(stack) - 1; i >= 0; i-- {
 		if n := stack[i]; n.Op == cur.Op {
 			if n != first {
-				sprint_depchain(fmt_, stack[:i], n, first)
+				sprint_depchain(trace, stack[:i], n, first)
 			}
-			*fmt_ += fmt.Sprintf("\n\t%v: %v uses %v", n.Line(), n, cur)
+			*trace += fmt.Sprintf("\n\t%v: %v uses %v", n.Line(), n, cur)
 			return
 		}
 	}
@@ -152,7 +152,6 @@
 	if n.Typecheck == 2 {
 		// Typechecking loop. Trying printing a meaningful message,
 		// otherwise a stack trace of typechecking.
-		var fmt_ string
 		switch n.Op {
 		// We can already diagnose variables used as types.
 		case ONAME:
@@ -160,22 +159,30 @@
 				yyerror("%v is not a type", n)
 			}
 
+		case OTYPE:
+			if top&Etype == Etype {
+				var trace string
+				sprint_depchain(&trace, typecheck_tcstack, n, n)
+				yyerrorl(n.Lineno, "invalid recursive type alias %v%s", n, trace)
+			}
+
 		case OLITERAL:
 			if top&(Erv|Etype) == Etype {
 				yyerror("%v is not a type", n)
 				break
 			}
-			sprint_depchain(&fmt_, typecheck_tcstack, n, n)
-			yyerrorl(n.Lineno, "constant definition loop%s", fmt_)
+			var trace string
+			sprint_depchain(&trace, typecheck_tcstack, n, n)
+			yyerrorl(n.Lineno, "constant definition loop%s", trace)
 		}
 
 		if nsavederrors+nerrors == 0 {
-			fmt_ = ""
+			var trace string
 			for i := len(typecheck_tcstack) - 1; i >= 0; i-- {
 				x := typecheck_tcstack[i]
-				fmt_ += fmt.Sprintf("\n\t%v %v", x.Line(), x)
+				trace += fmt.Sprintf("\n\t%v %v", x.Line(), x)
 			}
-			yyerror("typechecking loop involving %v%s", n, fmt_)
+			yyerror("typechecking loop involving %v%s", n, trace)
 		}
 
 		lineno = lno
@@ -3428,7 +3435,14 @@
 	t.SetNname(n.Func.Nname)
 	rcvr := t.Recv()
 	if rcvr != nil && n.Func.Shortname != nil {
-		addmethod(n.Func.Shortname.Sym, t, true, n.Func.Pragma&Nointerface != 0)
+		n.Func.Nname.Sym = methodname(n.Func.Shortname, rcvr.Type)
+		declare(n.Func.Nname, PFUNC)
+
+		addmethod(n.Func.Shortname, t, true, n.Func.Pragma&Nointerface != 0)
+	}
+
+	if Ctxt.Flag_dynlink && importpkg == nil && n.Func.Nname != nil {
+		makefuncsym(n.Func.Nname.Sym)
 	}
 }
 
@@ -3577,8 +3591,6 @@
 
 	// copy new type and clear fields
 	// that don't come along.
-	// anything zeroed here must be zeroed in
-	// typedcl2 too.
 	copytype(n, t)
 
 ret:
@@ -3757,12 +3769,29 @@
 		n.Name.Defn = typecheck(n.Name.Defn, Etop) // fills in n->type
 
 	case OTYPE:
+		if p := n.Name.Param; p.Alias {
+			// Type alias declaration: Simply use the rhs type - no need
+			// to create a new type.
+			// If we have a syntax error, p.Ntype may be nil.
+			if p.Ntype != nil {
+				p.Ntype = typecheck(p.Ntype, Etype)
+				n.Type = p.Ntype.Type
+				if n.Type == nil {
+					n.Diag = true
+					goto ret
+				}
+				n.Sym.Def = p.Ntype
+			}
+			break
+		}
+
+		// regular type declaration
 		if Curfn != nil {
 			defercheckwidth()
 		}
 		n.Walkdef = 1
 		n.Type = typ(TFORW)
-		n.Type.Sym = n.Sym
+		n.Type.Sym = n.Sym // TODO(gri) this also happens in typecheckdeftype(n) - where should it happen?
 		nerrors0 := nerrors
 		typecheckdeftype(n)
 		if n.Type.Etype == TFORW && nerrors > nerrors0 {
@@ -3770,7 +3799,6 @@
 			// but it was reported. Silence future errors.
 			n.Type.Broke = true
 		}
-
 		if Curfn != nil {
 			resumecheckwidth()
 		}
diff --git a/src/cmd/compile/internal/gc/universe.go b/src/cmd/compile/internal/gc/universe.go
index 30c9c37..d23aebe 100644
--- a/src/cmd/compile/internal/gc/universe.go
+++ b/src/cmd/compile/internal/gc/universe.go
@@ -398,6 +398,14 @@
 	// errortype.Orig = makeErrorInterface()
 	s.Def = typenod(errortype)
 
+	// We create separate byte and rune types for better error messages
+	// rather than just creating type alias *Sym's for the uint8 and
+	// int32 types. Hence, (bytetype|runtype).Sym.isAlias() is false.
+	// TODO(gri) Should we get rid of this special case (at the cost
+	// of less informative error messages involving bytes and runes)?
+	// (Alternatively, we could introduce an OTALIAS node representing
+	// type aliases, albeit at the cost of having to deal with it everywhere).
+
 	// byte alias
 	s = Pkglookup("byte", builtinpkg)
 	bytetype = typ(TUINT8)
diff --git a/src/cmd/compile/internal/syntax/nodes.go b/src/cmd/compile/internal/syntax/nodes.go
index fadba84..34524e5 100644
--- a/src/cmd/compile/internal/syntax/nodes.go
+++ b/src/cmd/compile/internal/syntax/nodes.go
@@ -74,6 +74,7 @@
 	// Name Type
 	TypeDecl struct {
 		Name   *Name
+		Alias  bool
 		Type   Expr
 		Group  *Group // nil means not part of a group
 		Pragma Pragma
diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go
index e45ca05..b6e6c77 100644
--- a/src/cmd/compile/internal/syntax/parser.go
+++ b/src/cmd/compile/internal/syntax/parser.go
@@ -325,7 +325,7 @@
 	return d
 }
 
-// TypeSpec = identifier Type .
+// TypeSpec = identifier [ "=" ] Type .
 func (p *parser) typeDecl(group *Group) Decl {
 	if trace {
 		defer p.trace("typeDecl")()
@@ -335,6 +335,7 @@
 	d.init(p)
 
 	d.Name = p.name()
+	d.Alias = p.got(_Assign)
 	d.Type = p.tryType()
 	if d.Type == nil {
 		p.syntax_error("in type declaration")
diff --git a/src/cmd/compile/internal/syntax/printer.go b/src/cmd/compile/internal/syntax/printer.go
index 0cacf1e..43876a2 100644
--- a/src/cmd/compile/internal/syntax/printer.go
+++ b/src/cmd/compile/internal/syntax/printer.go
@@ -619,7 +619,11 @@
 		if n.Group == nil {
 			p.print(_Type, blank)
 		}
-		p.print(n.Name, blank, n.Type)
+		p.print(n.Name, blank)
+		if n.Alias {
+			p.print(_Assign, blank)
+		}
+		p.print(n.Type)
 
 	case *VarDecl:
 		if n.Group == nil {
diff --git a/src/cmd/compile/internal/syntax/printer_test.go b/src/cmd/compile/internal/syntax/printer_test.go
index 5c0fc77..a9969e6 100644
--- a/src/cmd/compile/internal/syntax/printer_test.go
+++ b/src/cmd/compile/internal/syntax/printer_test.go
@@ -22,3 +22,20 @@
 	Fprint(os.Stdout, ast, true)
 	fmt.Println()
 }
+
+func TestPrintString(t *testing.T) {
+	for _, want := range []string{
+		"package p",
+		"package p; type _ = int; type T1 = struct{}; type ( _ = *struct{}; T2 = float32 )",
+		// TODO(gri) expand
+	} {
+		ast, err := ParseBytes([]byte(want), nil, nil, 0)
+		if err != nil {
+			t.Error(err)
+			continue
+		}
+		if got := String(ast); got != want {
+			t.Errorf("%q: got %q", want, got)
+		}
+	}
+}
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go
index c51dcea..f97f81e 100644
--- a/src/cmd/dist/test.go
+++ b/src/cmd/dist/test.go
@@ -600,6 +600,7 @@
 			})
 		}
 	}
+	return // skip API check on go1.8.typealias branch
 	if t.goos != "nacl" && t.goos != "android" && !t.iOS() {
 		t.tests = append(t.tests, distTest{
 			name:    "api",
diff --git a/src/cmd/doc/doc_test.go b/src/cmd/doc/doc_test.go
index 1c054fd..1244476 100644
--- a/src/cmd/doc/doc_test.go
+++ b/src/cmd/doc/doc_test.go
@@ -71,6 +71,7 @@
 			`const MultiLineConst = ...`,                                   // Multi line constant.
 			`var MultiLineVar = map\[struct{ ... }\]struct{ ... }{ ... }`,  // Multi line variable.
 			`func MultiLineFunc\(x interface{ ... }\) \(r struct{ ... }\)`, // Multi line function.
+			`type T1 = T2`, // Type alias
 		},
 		[]string{
 			`const internalConstant = 2`,        // No internal constants.
@@ -89,6 +90,7 @@
 			`unexportedTypedConstant`,           // No unexported typed constant.
 			`Field`,                             // No fields.
 			`Method`,                            // No methods.
+			`type T1 T2`, // Type alias does not display as type declaration.
 		},
 	},
 	// Package dump -u
@@ -265,6 +267,18 @@
 			`error`,                          // No embedded error.
 		},
 	},
+	// Type T1 dump (alias).
+	{
+		"type T1",
+		[]string{p+".T1"},
+		[]string{
+			`type T1 = T2`,
+		},
+		[]string{
+			`type T1 T2`,
+			`type ExportedType`,
+		},
+	},
 	// Type -u with unexported fields.
 	{
 		"type with unexported fields and -u",
diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go
index daa6ed3..32d08f21 100644
--- a/src/cmd/doc/pkg.go
+++ b/src/cmd/doc/pkg.go
@@ -258,7 +258,11 @@
 		return fmt.Sprintf("func %s%s%s", recv, name, fnc)
 
 	case *ast.TypeSpec:
-		return fmt.Sprintf("type %s %s", n.Name.Name, pkg.oneLineNodeDepth(n.Type, depth))
+		sep := " "
+		if n.Assign.IsValid() {
+			sep = " = "
+		}
+		return fmt.Sprintf("type %s%s%s", n.Name.Name, sep, pkg.oneLineNodeDepth(n.Type, depth))
 
 	case *ast.FuncType:
 		var params []string
diff --git a/src/cmd/doc/testdata/pkg.go b/src/cmd/doc/testdata/pkg.go
index 924daa1..0ebea67 100644
--- a/src/cmd/doc/testdata/pkg.go
+++ b/src/cmd/doc/testdata/pkg.go
@@ -172,3 +172,7 @@
 )
 
 const ConstGroup4 ExportedType = ExportedType{}
+
+type T2 int
+
+type T1 = T2
diff --git a/src/cmd/gofmt/testdata/typealias.golden b/src/cmd/gofmt/testdata/typealias.golden
new file mode 100644
index 0000000..bbbbf32
--- /dev/null
+++ b/src/cmd/gofmt/testdata/typealias.golden
@@ -0,0 +1,24 @@
+package q
+
+import "p"
+
+type _ = int
+type a = struct{ x int }
+type b = p.B
+
+type (
+	_  = chan<- int
+	aa = interface{}
+	bb = p.BB
+)
+
+// TODO(gri) We may want to put the '=' into a separate column if
+// we have mixed (regular and alias) type declarations in a group.
+type (
+	_   chan<- int
+	_   = chan<- int
+	aa0 interface{}
+	aaa = interface{}
+	bb0 p.BB
+	bbb = p.BB
+)
diff --git a/src/cmd/gofmt/testdata/typealias.input b/src/cmd/gofmt/testdata/typealias.input
new file mode 100644
index 0000000..6e49328
--- /dev/null
+++ b/src/cmd/gofmt/testdata/typealias.input
@@ -0,0 +1,24 @@
+package q
+
+import "p"
+
+type _ = int
+type a = struct{ x int }
+type b = p.B
+
+type (
+	_ = chan<- int
+	aa = interface{}
+	bb = p.BB
+)
+
+// TODO(gri) We may want to put the '=' into a separate column if
+// we have mixed (regular and alias) type declarations in a group.
+type (
+	_ chan<- int
+	_ = chan<- int
+	aa0 interface{}
+	aaa = interface{}
+	bb0 p.BB
+	bbb = p.BB
+)
diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go
index d111b00..d898c40 100644
--- a/src/cmd/link/internal/ld/decodesym.go
+++ b/src/cmd/link/internal/ld/decodesym.go
@@ -255,7 +255,7 @@
 
 func decodetypeStructFieldOffs(arch *sys.Arch, s *Symbol, i int) int64 {
 	off := decodetypeStructFieldArrayOff(s, i)
-	return int64(decodeInuxi(arch, s.P[off+2*SysArch.PtrSize:], SysArch.IntSize))
+	return int64(decodeInuxi(arch, s.P[off+2*SysArch.PtrSize:], SysArch.IntSize) >> 1)
 }
 
 // InterfaceType.methods.length
diff --git a/src/go/ast/ast.go b/src/go/ast/ast.go
index a197b5a..2ecc48b 100644
--- a/src/go/ast/ast.go
+++ b/src/go/ast/ast.go
@@ -848,6 +848,7 @@
 	TypeSpec struct {
 		Doc     *CommentGroup // associated documentation; or nil
 		Name    *Ident        // type name
+		Assign  token.Pos     // position of '=', if any
 		Type    Expr          // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes
 		Comment *CommentGroup // line comments; or nil
 	}
diff --git a/src/go/build/build.go b/src/go/build/build.go
index f11bc0c..fdd0735 100644
--- a/src/go/build/build.go
+++ b/src/go/build/build.go
@@ -290,7 +290,8 @@
 	// in all releases >= Go 1.x. Code that requires Go 1.x or later should
 	// say "+build go1.x", and code that should only be built before Go 1.x
 	// (perhaps it is the stub to use in that case) should say "+build !go1.x".
-	c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6", "go1.7", "go1.8"}
+	// NOTE: If you add to this list, also update the doc comment in doc.go.
+	c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6", "go1.7", "go1.8", "go1.8.typealias"}
 
 	env := os.Getenv("CGO_ENABLED")
 	if env == "" {
diff --git a/src/go/build/doc.go b/src/go/build/doc.go
index 979d047..5bdba44 100644
--- a/src/go/build/doc.go
+++ b/src/go/build/doc.go
@@ -105,6 +105,7 @@
 //	- "go1.6", from Go version 1.6 onward
 //	- "go1.7", from Go version 1.7 onward
 //	- "go1.8", from Go version 1.8 onward
+//	- "go1.8.typealias", for Go version 1.8 with aliases
 //	- any additional words listed in ctxt.BuildTags
 //
 // If a file's name, after stripping the extension and a possible _test suffix,
diff --git a/src/go/internal/gccgoimporter/importer_test.go b/src/go/internal/gccgoimporter/importer_test.go
index 2b45470..4fca828 100644
--- a/src/go/internal/gccgoimporter/importer_test.go
+++ b/src/go/internal/gccgoimporter/importer_test.go
@@ -101,6 +101,7 @@
 	{pkgpath: "unicode", name: "IsUpper", want: "func IsUpper(r rune) bool"},
 	{pkgpath: "unicode", name: "MaxRune", want: "const MaxRune untyped rune", wantval: "1114111"},
 	{pkgpath: "imports", wantinits: []string{"imports..import", "fmt..import", "math..import"}},
+	{pkgpath: "alias", name: "IntAlias2", want: "type IntAlias2 = Int"},
 }
 
 func TestGoxImporter(t *testing.T) {
diff --git a/src/go/internal/gccgoimporter/parser.go b/src/go/internal/gccgoimporter/parser.go
index 3b97c96..0d78865 100644
--- a/src/go/internal/gccgoimporter/parser.go
+++ b/src/go/internal/gccgoimporter/parser.go
@@ -370,27 +370,41 @@
 	return types.NewConst(token.NoPos, pkg, name, typ, val)
 }
 
-// TypeName = ExportedName .
-func (p *parser) parseTypeName() *types.TypeName {
-	pkg, name := p.parseExportedName()
-	scope := pkg.Scope()
-	if obj := scope.Lookup(name); obj != nil {
-		return obj.(*types.TypeName)
-	}
-	obj := types.NewTypeName(token.NoPos, pkg, name, nil)
-	// a named type may be referred to before the underlying type
-	// is known - set it up
-	types.NewNamed(obj, nil, nil)
-	scope.Insert(obj)
-	return obj
-}
-
-// NamedType = TypeName Type { Method } .
+// NamedType = TypeName [ "=" ] Type { Method } .
+// TypeName  = ExportedName .
 // Method    = "func" "(" Param ")" Name ParamList ResultList ";" .
 func (p *parser) parseNamedType(n int) types.Type {
-	obj := p.parseTypeName()
+	pkg, name := p.parseExportedName()
+	scope := pkg.Scope()
 
-	pkg := obj.Pkg()
+	if p.tok == '=' {
+		// type alias
+		p.next()
+		typ := p.parseType(pkg)
+		if obj := scope.Lookup(name); obj != nil {
+			typ = obj.Type() // use previously imported type
+			if typ == nil {
+				p.errorf("%v (type alias) used in cycle", obj)
+			}
+		} else {
+			obj = types.NewTypeName(token.NoPos, pkg, name, typ)
+			scope.Insert(obj)
+		}
+		p.typeMap[n] = typ
+		return typ
+	}
+
+	// named type
+	obj := scope.Lookup(name)
+	if obj == nil {
+		// a named type may be referred to before the underlying type
+		// is known - set it up
+		tname := types.NewTypeName(token.NoPos, pkg, name, nil)
+		types.NewNamed(tname, nil, nil)
+		scope.Insert(tname)
+		obj = tname
+	}
+
 	typ := obj.Type()
 	p.typeMap[n] = typ
 
@@ -409,8 +423,8 @@
 		nt.SetUnderlying(underlying.Underlying())
 	}
 
+	// collect associated methods
 	for p.tok == scanner.Ident {
-		// collect associated methods
 		p.expectKeyword("func")
 		p.expect('(')
 		receiver, _ := p.parseParam(pkg)
diff --git a/src/go/internal/gccgoimporter/testdata/alias.gox b/src/go/internal/gccgoimporter/testdata/alias.gox
new file mode 100644
index 0000000..ced7d84
--- /dev/null
+++ b/src/go/internal/gccgoimporter/testdata/alias.gox
@@ -0,0 +1,4 @@
+v1;
+package alias;
+pkgpath alias;
+type <type 115 "I1" <type 116 interface { M1 (? <type 117 "IntAlias2" = <type 118 "IntAlias" = <type 119 "Int" <type -11>>>>) < type 114>; M2 () <type 1>; }>>;
diff --git a/src/go/internal/gcimporter/bimport.go b/src/go/internal/gcimporter/bimport.go
index a8f3490..5badd33 100644
--- a/src/go/internal/gcimporter/bimport.go
+++ b/src/go/internal/gcimporter/bimport.go
@@ -98,10 +98,10 @@
 
 	// read version specific flags - extend as necessary
 	switch p.version {
-	// case 4:
+	// case 5:
 	// 	...
 	//	fallthrough
-	case 3, 2, 1:
+	case 4, 3, 2, 1:
 		p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
 		p.trackAllTypes = p.int() != 0
 		p.posInfoFormat = p.int() != 0
@@ -208,7 +208,6 @@
 }
 
 // objTag returns the tag value for each object kind.
-// obj must not be a *types.Alias.
 func objTag(obj types.Object) int {
 	switch obj.(type) {
 	case *types.Const:
@@ -219,7 +218,6 @@
 		return varTag
 	case *types.Func:
 		return funcTag
-	// Aliases are not exported multiple times, thus we should not see them here.
 	default:
 		errorf("unexpected object: %v (%T)", obj, obj) // panics
 		panic("unreachable")
@@ -237,14 +235,14 @@
 	pkg := obj.Pkg()
 	if alt := pkg.Scope().Insert(obj); alt != nil {
 		// This can only trigger if we import a (non-type) object a second time.
-		// Excluding aliases, this cannot happen because 1) we only import a package
+		// Excluding type aliases, this cannot happen because 1) we only import a package
 		// once; and b) we ignore compiler-specific export data which may contain
 		// functions whose inlined function bodies refer to other functions that
 		// were already imported.
-		// However, aliases require reexporting the original object, so we need
+		// However, type aliases require reexporting the original type, so we need
 		// to allow it (see also the comment in cmd/compile/internal/gc/bimport.go,
 		// method importer.obj, switch case importing functions).
-		// Note that the original itself cannot be an alias.
+		// TODO(gri) review/update this comment once the gc compiler handles type aliases.
 		if !sameObj(obj, alt) {
 			errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", obj, alt)
 		}
@@ -260,6 +258,13 @@
 		val := p.value()
 		p.declare(types.NewConst(pos, pkg, name, typ, val))
 
+	case aliasTag:
+		// TODO(gri) verify type alias hookup is correct
+		pos := p.pos()
+		pkg, name := p.qualifiedName()
+		typ := p.typ(nil)
+		p.declare(types.NewTypeName(pos, pkg, name, typ))
+
 	case typeTag:
 		p.typ(nil)
 
@@ -277,19 +282,6 @@
 		sig := types.NewSignature(nil, params, result, isddd)
 		p.declare(types.NewFunc(pos, pkg, name, sig))
 
-	case aliasTag:
-		pos := p.pos()
-		name := p.string()
-		var orig types.Object
-		if pkg, name := p.qualifiedName(); pkg != nil {
-			orig = pkg.Scope().Lookup(name)
-		}
-		// Alias-related code. Keep for now.
-		_ = pos
-		_ = name
-		_ = orig
-		// p.declare(types.NewAlias(pos, p.pkgList[0], name, orig))
-
 	default:
 		errorf("unexpected object tag %d", tag)
 	}
@@ -349,9 +341,7 @@
 
 func (p *importer) qualifiedName() (pkg *types.Package, name string) {
 	name = p.string()
-	if name != "" {
-		pkg = p.pkg()
-	}
+	pkg = p.pkg()
 	return
 }
 
@@ -556,17 +546,17 @@
 		fields = make([]*types.Var, n)
 		tags = make([]string, n)
 		for i := range fields {
-			fields[i] = p.field(parent)
-			tags[i] = p.string()
+			fields[i], tags[i] = p.field(parent)
 		}
 	}
 	return
 }
 
-func (p *importer) field(parent *types.Package) *types.Var {
+func (p *importer) field(parent *types.Package) (*types.Var, string) {
 	pos := p.pos()
-	pkg, name := p.fieldName(parent)
+	pkg, name, alias := p.fieldName(parent)
 	typ := p.typ(parent)
+	tag := p.string()
 
 	anonymous := false
 	if name == "" {
@@ -578,12 +568,15 @@
 		case *types.Named:
 			name = typ.Obj().Name()
 		default:
-			errorf("anonymous field expected")
+			errorf("named base type expected")
 		}
 		anonymous = true
+	} else if alias {
+		// anonymous field: we have an explicit name because it's an alias
+		anonymous = true
 	}
 
-	return types.NewField(pos, pkg, name, typ, anonymous)
+	return types.NewField(pos, pkg, name, typ, anonymous), tag
 }
 
 func (p *importer) methodList(parent *types.Package) (methods []*types.Func) {
@@ -598,31 +591,42 @@
 
 func (p *importer) method(parent *types.Package) *types.Func {
 	pos := p.pos()
-	pkg, name := p.fieldName(parent)
+	pkg, name, _ := p.fieldName(parent)
 	params, isddd := p.paramList()
 	result, _ := p.paramList()
 	sig := types.NewSignature(nil, params, result, isddd)
 	return types.NewFunc(pos, pkg, name, sig)
 }
 
-func (p *importer) fieldName(parent *types.Package) (*types.Package, string) {
-	name := p.string()
-	pkg := parent
+func (p *importer) fieldName(parent *types.Package) (pkg *types.Package, name string, alias bool) {
+	name = p.string()
+	pkg = parent
 	if pkg == nil {
 		// use the imported package instead
 		pkg = p.pkgList[0]
 	}
 	if p.version == 0 && name == "_" {
 		// version 0 didn't export a package for _ fields
-		return pkg, name
+		return
 	}
-	if name != "" && !exported(name) {
-		if name == "?" {
-			name = ""
-		}
+	switch name {
+	case "":
+		// 1) field name matches base type name and is exported: nothing to do
+	case "?":
+		// 2) field name matches base type name and is not exported: need package
+		name = ""
 		pkg = p.pkg()
+	case "@":
+		// 3) field name doesn't match type name (alias)
+		name = p.string()
+		alias = true
+		fallthrough
+	default:
+		if !exported(name) {
+			pkg = p.pkg()
+		}
 	}
-	return pkg, name
+	return
 }
 
 func (p *importer) paramList() (*types.Tuple, bool) {
@@ -893,7 +897,7 @@
 	nilTag     // only used by gc (appears in exported inlined function bodies)
 	unknownTag // not used by gc (only appears in packages with errors)
 
-	// Aliases
+	// Type aliases
 	aliasTag
 )
 
@@ -917,7 +921,7 @@
 	types.Typ[types.Complex128],
 	types.Typ[types.String],
 
-	// aliases
+	// basic type aliases
 	types.Universe.Lookup("byte").Type(),
 	types.Universe.Lookup("rune").Type(),
 
diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go
index d3ef7db..40c4a3e 100644
--- a/src/go/parser/parser.go
+++ b/src/go/parser/parser.go
@@ -2327,7 +2327,10 @@
 	// (Global identifiers are resolved in a separate phase after parsing.)
 	spec := &ast.TypeSpec{Doc: doc, Name: ident}
 	p.declare(spec, nil, p.topScope, ast.Typ, ident)
-
+	if p.tok == token.ASSIGN {
+		spec.Assign = p.pos
+		p.next()
+	}
 	spec.Type = p.parseType()
 	p.expectSemi() // call before accessing p.linecomment
 	spec.Comment = p.lineComment
diff --git a/src/go/parser/short_test.go b/src/go/parser/short_test.go
index cdd343e..6f8ef6b 100644
--- a/src/go/parser/short_test.go
+++ b/src/go/parser/short_test.go
@@ -46,6 +46,8 @@
 	`package p; const (x = 0; y; z)`, // issue 9639
 	`package p; var _ = map[P]int{P{}:0, {}:1}`,
 	`package p; var _ = map[*P]int{&P{}:0, {}:1}`,
+	`package p; type T = int`,
+	`package p; type (T = p.T; _ = struct{}; x = *T)`,
 }
 
 func TestValid(t *testing.T) {
diff --git a/src/go/printer/nodes.go b/src/go/printer/nodes.go
index ea43286..08b8711 100644
--- a/src/go/printer/nodes.go
+++ b/src/go/printer/nodes.go
@@ -1447,6 +1447,9 @@
 		} else {
 			p.print(vtab)
 		}
+		if s.Assign.IsValid() {
+			p.print(token.ASSIGN, blank)
+		}
 		p.expr(s.Type)
 		p.setComment(s.Comment)
 
diff --git a/src/go/printer/testdata/declarations.golden b/src/go/printer/testdata/declarations.golden
index 82f5e0f..d4ea545 100644
--- a/src/go/printer/testdata/declarations.golden
+++ b/src/go/printer/testdata/declarations.golden
@@ -985,3 +985,18 @@
 	x	int
 	y	int
 })	// no extra comma between } and )
+
+// alias declarations
+
+type c0 struct{}
+type c1 = C
+type c2 = struct{ x int }
+type c3 = p.C
+type (
+	s	struct{}
+	a	= A
+	b	= A
+	c	= foo
+	d	= interface{}
+	ddd	= p.Foo
+)
diff --git a/src/go/printer/testdata/declarations.input b/src/go/printer/testdata/declarations.input
index a0a3783..50386eb 100644
--- a/src/go/printer/testdata/declarations.input
+++ b/src/go/printer/testdata/declarations.input
@@ -999,3 +999,18 @@
 	x int
 	y int
 }) // no extra comma between } and )
+
+// alias declarations
+
+type c0 struct{}
+type c1 = C
+type c2 = struct{ x int}
+type c3 = p.C
+type (
+	s struct{}
+	a = A
+	b = A
+	c = foo
+	d = interface{}
+	ddd = p.Foo
+)
\ No newline at end of file
diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go
index 1208eb8..92c6d75 100644
--- a/src/go/types/api_test.go
+++ b/src/go/types/api_test.go
@@ -1295,155 +1295,3 @@
 		}
 	}
 }
-
-// Alias-related code. Keep for now.
-/*
-func TestAliases(t *testing.T) {
-	testenv.MustHaveGoBuild(t)
-
-	const src = `
-package b
-
-import (
-	"./testdata/alias"
-	a "./testdata/alias"
-	"math"
-)
-
-const (
-	c1 = alias.Pi1
-	c2 => a.Pi1
-	c3 => a.Pi2
-	c4 => math.Pi
-)
-
-var (
-	v1 => alias.Default
-	v2 => a.Default
-	v3 = f1
-)
-
-type (
-	t1 => alias.Context
-	t2 => a.Context
-)
-
-func f1 => alias.Sin
-func f2 => a.Sin
-
-func _() {
-	assert(c1 == alias.Pi1 && c2 == a.Pi1 && c3 == a.Pi2 && c4 == math.Pi)
-	assert(c2 == c2 && c2 == c3 && c3 == c4)
-	v1 = v2 // must be assignable
-	var _ *t1 = new(t2) // must be assignable
-	var _ t2 = alias.Default
-	f1(1) // must be callable
-	f2(1)
-	_ = alias.Sin(1)
-	_ = a.Sin(1)
-}
-`
-
-	if out := compile(t, "testdata", "alias.go"); out != "" {
-		defer os.Remove(out)
-	}
-
-	DefPredeclaredTestFuncs() // declare assert built-in for testing
-	mustTypecheck(t, "Aliases", src, nil)
-}
-
-func compile(t *testing.T, dirname, filename string) string {
-	cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", filename)
-	cmd.Dir = dirname
-	out, err := cmd.CombinedOutput()
-	if err != nil {
-		t.Logf("%s", out)
-		t.Fatalf("go tool compile %s failed: %s", filename, err)
-	}
-	// filename should end with ".go"
-	return filepath.Join(dirname, filename[:len(filename)-2]+"o")
-}
-
-func TestAliasDefUses(t *testing.T) {
-	testenv.MustHaveGoBuild(t)
-
-	const src = `
-package p
-
-import(
-	"go/build"
-	"go/types"
-)
-
-// Defs
-const Invalid => types.Invalid
-type Struct => types.Struct
-var Default => build.Default
-func Implements => types.Implements
-
-// Uses
-const _ = Invalid
-var _ types.Struct = Struct{} // types must be identical
-var _ build.Context = Default
-var _ = Implements(nil, nil)
-`
-
-	info := Info{
-		Defs: make(map[*ast.Ident]Object),
-		Uses: make(map[*ast.Ident]Object),
-	}
-	mustTypecheck(t, "TestAliasDefUses", src, &info)
-
-	// verify Defs
-	defs := map[string]string{
-		"Invalid":    "types.Invalid",
-		"Struct":     "types.Struct",
-		"Default":    "build.Default",
-		"Implements": "types.Implements",
-	}
-
-	for ident, obj := range info.Defs {
-		if alias, ok := obj.(*Alias); ok {
-			if want := defs[ident.Name]; want != "" {
-				orig := alias.Orig()
-				if got := orig.Pkg().Name() + "." + orig.Name(); got != want {
-					t.Errorf("%v: got %v, want %v", ident, got, want)
-				}
-				delete(defs, ident.Name) // mark as found
-			} else {
-				t.Errorf("unexpected alias def of %v", ident)
-			}
-		}
-	}
-
-	if len(defs) != 0 {
-		t.Errorf("missing aliases: %v", defs)
-	}
-
-	// verify Uses
-	uses := map[string]string{
-		"Invalid":    "types.Invalid",
-		"Struct":     "types.Struct",
-		"Default":    "build.Default",
-		"Implements": "types.Implements",
-	}
-
-	for ident, obj := range info.Uses {
-		if alias, ok := obj.(*Alias); ok {
-			if want := uses[ident.Name]; want != "" {
-				orig := alias.Orig()
-				if got := orig.Pkg().Name() + "." + orig.Name(); got != want {
-					t.Errorf("%v: got %v, want %v", ident, got, want)
-				}
-				delete(uses, ident.Name) // mark as found
-			} else {
-				t.Errorf("unexpected alias use of %v", ident)
-			}
-		}
-	}
-
-	if len(uses) != 0 {
-		t.Errorf("missing aliases: %v", defs)
-	}
-}
-*/
diff --git a/src/go/types/call.go b/src/go/types/call.go
index 8e5c537..7f5823c 100644
--- a/src/go/types/call.go
+++ b/src/go/types/call.go
@@ -275,8 +275,6 @@
 	// so we don't need a "package" mode for operands: package names
 	// can only appear in qualified identifiers which are mapped to
 	// selector expressions.
-	// (see also decl.go: checker.aliasDecl)
-	// TODO(gri) factor this code out and share with checker.aliasDecl
 	if ident, ok := e.X.(*ast.Ident); ok {
 		_, obj := check.scope.LookupParent(ident.Name, check.pos)
 		if pname, _ := obj.(*PkgName); pname != nil {
@@ -296,12 +294,6 @@
 				// ok to continue
 			}
 			check.recordUse(e.Sel, exp)
-			exp = original(exp)
-
-			// avoid further errors if the imported object is an alias that's broken
-			if exp == nil {
-				goto Error
-			}
 
 			// Simplified version of the code for *ast.Idents:
 			// - imported objects are always fully initialized
diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go
index f844575..24b3365 100644
--- a/src/go/types/check_test.go
+++ b/src/go/types/check_test.go
@@ -68,11 +68,11 @@
 	{"testdata/decls1.src"},
 	{"testdata/decls2a.src", "testdata/decls2b.src"},
 	{"testdata/decls3.src"},
+	{"testdata/decls4.src"},
 	{"testdata/const0.src"},
 	{"testdata/const1.src"},
 	{"testdata/constdecl.src"},
 	{"testdata/vardecl.src"},
-	//{"testdata/aliasdecl.src"},
 	{"testdata/expr0.src"},
 	{"testdata/expr1.src"},
 	{"testdata/expr2.src"},
diff --git a/src/go/types/decl.go b/src/go/types/decl.go
index dced7a6..7428f8f 100644
--- a/src/go/types/decl.go
+++ b/src/go/types/decl.go
@@ -81,14 +81,10 @@
 		check.varDecl(obj, d.lhs, d.typ, d.init)
 	case *TypeName:
 		// invalid recursive types are detected via path
-		check.typeDecl(obj, d.typ, def, path)
+		check.typeDecl(obj, d.typ, def, path, d.alias)
 	case *Func:
 		// functions may be recursive - no need to track dependencies
 		check.funcDecl(obj, d)
-	// Alias-related code. Keep for now.
-	// case *Alias:
-	// 	// aliases cannot be recursive - no need to track dependencies
-	// 	check.aliasDecl(obj, d)
 	default:
 		unreachable()
 	}
@@ -219,33 +215,42 @@
 	}
 }
 
-func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, path []*TypeName) {
+func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, path []*TypeName, alias bool) {
 	assert(obj.typ == nil)
 
 	// type declarations cannot use iota
 	assert(check.iota == nil)
 
-	named := &Named{obj: obj}
-	def.setUnderlying(named)
-	obj.typ = named // make sure recursive type declarations terminate
+	if alias {
 
-	// determine underlying type of named
-	check.typExpr(typ, named, append(path, obj))
+		obj.typ = Typ[Invalid]
+		obj.typ = check.typExpr(typ, nil, append(path, obj))
 
-	// The underlying type of named may be itself a named type that is
-	// incomplete:
-	//
-	//	type (
-	//		A B
-	//		B *C
-	//		C A
-	//	)
-	//
-	// The type of C is the (named) type of A which is incomplete,
-	// and which has as its underlying type the named type B.
-	// Determine the (final, unnamed) underlying type by resolving
-	// any forward chain (they always end in an unnamed type).
-	named.underlying = underlying(named.underlying)
+	} else {
+
+		named := &Named{obj: obj}
+		def.setUnderlying(named)
+		obj.typ = named // make sure recursive type declarations terminate
+
+		// determine underlying type of named
+		check.typExpr(typ, named, append(path, obj))
+
+		// The underlying type of named may be itself a named type that is
+		// incomplete:
+		//
+		//	type (
+		//		A B
+		//		B *C
+		//		C A
+		//	)
+		//
+		// The type of C is the (named) type of A which is incomplete,
+		// and which has as its underlying type the named type B.
+		// Determine the (final, unnamed) underlying type by resolving
+		// any forward chain (they always end in an unnamed type).
+		named.underlying = underlying(named.underlying)
+
+	}
 
 	// check and add associated methods
 	// TODO(gri) It's easy to create pathological cases where the
@@ -268,21 +273,23 @@
 
 	// spec: "If the base type is a struct type, the non-blank method
 	// and field names must be distinct."
-	base := obj.typ.(*Named)
-	if t, _ := base.underlying.(*Struct); t != nil {
-		for _, fld := range t.fields {
-			if fld.name != "_" {
-				assert(mset.insert(fld) == nil)
+	base, _ := obj.typ.(*Named) // nil if receiver base type is type alias
+	if base != nil {
+		if t, _ := base.underlying.(*Struct); t != nil {
+			for _, fld := range t.fields {
+				if fld.name != "_" {
+					assert(mset.insert(fld) == nil)
+				}
 			}
 		}
-	}
 
-	// Checker.Files may be called multiple times; additional package files
-	// may add methods to already type-checked types. Add pre-existing methods
-	// so that we can detect redeclarations.
-	for _, m := range base.methods {
-		assert(m.name != "_")
-		assert(mset.insert(m) == nil)
+		// Checker.Files may be called multiple times; additional package files
+		// may add methods to already type-checked types. Add pre-existing methods
+		// so that we can detect redeclarations.
+		for _, m := range base.methods {
+			assert(m.name != "_")
+			assert(mset.insert(m) == nil)
+		}
 	}
 
 	// type-check methods
@@ -295,7 +302,7 @@
 				case *Var:
 					check.errorf(m.pos, "field and method with the same name %s", m.name)
 				case *Func:
-					check.errorf(m.pos, "method %s already declared for %s", m.name, base)
+					check.errorf(m.pos, "method %s already declared for %s", m.name, obj)
 				default:
 					unreachable()
 				}
@@ -303,9 +310,12 @@
 				continue
 			}
 		}
+
+		// type-check
 		check.objDecl(m, nil, nil)
+
 		// methods with blank _ names cannot be found - don't keep them
-		if m.name != "_" {
+		if base != nil && m.name != "_" {
 			base.methods = append(base.methods, m)
 		}
 	}
@@ -333,106 +343,6 @@
 	}
 }
 
-// original returns the original Object if obj is an Alias;
-// otherwise it returns obj. The result is never an Alias,
-// but it may be nil.
-func original(obj Object) Object {
-	// an alias stands for the original object; use that one instead
-	if alias, _ := obj.(*disabledAlias); alias != nil {
-		obj = alias.orig
-		// aliases always refer to non-alias originals
-		if _, ok := obj.(*disabledAlias); ok {
-			panic("original is an alias")
-		}
-	}
-	return obj
-}
-
-func (check *Checker) aliasDecl(obj *disabledAlias, decl *declInfo) {
-	assert(obj.typ == nil)
-
-	// alias declarations cannot use iota
-	assert(check.iota == nil)
-
-	// assume alias is invalid to start with
-	obj.typ = Typ[Invalid]
-
-	// rhs must be package-qualified identifer pkg.sel (see also call.go: checker.selector)
-	// TODO(gri) factor this code out and share with checker.selector
-	rhs := decl.init
-	var pkg *Package
-	var sel *ast.Ident
-	if sexpr, ok := rhs.(*ast.SelectorExpr); ok {
-		if ident, ok := sexpr.X.(*ast.Ident); ok {
-			_, obj := check.scope.LookupParent(ident.Name, check.pos)
-			if pname, _ := obj.(*PkgName); pname != nil {
-				assert(pname.pkg == check.pkg)
-				check.recordUse(ident, pname)
-				pname.used = true
-				pkg = pname.imported
-				sel = sexpr.Sel
-			}
-		}
-	}
-	if pkg == nil {
-		check.errorf(rhs.Pos(), "invalid alias: %v is not a package-qualified identifier", rhs)
-		return
-	}
-
-	// qualified identifier must denote an exported object
-	orig := pkg.scope.Lookup(sel.Name)
-	if orig == nil || !orig.Exported() {
-		if !pkg.fake {
-			check.errorf(rhs.Pos(), "%s is not exported by package %s", sel.Name, pkg.name)
-		}
-		return
-	}
-	check.recordUse(sel, orig)
-	orig = original(orig)
-
-	// avoid further errors if the imported object is an alias that's broken
-	if orig == nil {
-		return
-	}
-
-	// An alias declaration must not refer to package unsafe.
-	if orig.Pkg() == Unsafe {
-		check.errorf(rhs.Pos(), "invalid alias: %s refers to package unsafe (%v)", obj.Name(), orig)
-		return
-	}
-
-	// The original must be of the same kind as the alias declaration.
-	var why string
-	switch obj.kind {
-	case token.CONST:
-		if _, ok := orig.(*Const); !ok {
-			why = "constant"
-		}
-	case token.TYPE:
-		if _, ok := orig.(*TypeName); !ok {
-			why = "type"
-		}
-	case token.VAR:
-		if _, ok := orig.(*Var); !ok {
-			why = "variable"
-		}
-	case token.FUNC:
-		if _, ok := orig.(*Func); !ok {
-			why = "function"
-		}
-	default:
-		unreachable()
-	}
-	if why != "" {
-		check.errorf(rhs.Pos(), "invalid alias: %v is not a %s", orig, why)
-		return
-	}
-
-	// alias is valid
-	obj.typ = orig.Type()
-	obj.orig = orig
-}
-
 func (check *Checker) declStmt(decl ast.Decl) {
 	pkg := check.pkg
 
@@ -540,7 +450,7 @@
 				// the innermost containing block."
 				scopePos := s.Name.Pos()
 				check.declare(check.scope, s.Name, obj, scopePos)
-				check.typeDecl(obj, s.Type, nil, nil)
+				check.typeDecl(obj, s.Type, nil, nil, s.Assign.IsValid())
 
 			default:
 				check.invalidAST(s.Pos(), "const, type, or var declaration expected")
diff --git a/src/go/types/example_test.go b/src/go/types/example_test.go
index 8882e50..2a2fb3f 100644
--- a/src/go/types/example_test.go
+++ b/src/go/types/example_test.go
@@ -239,10 +239,10 @@
 	// type S string:
 	//   defined at fib.go:4:6
 	//   used at 6:23
-	// type int int:
+	// type int:
 	//   defined at -
 	//   used at 8:12, 8:17
-	// type string string:
+	// type string:
 	//   defined at -
 	//   used at 4:8
 	// var b S:
diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go
index 3caca55..ee8202d 100644
--- a/src/go/types/lookup.go
+++ b/src/go/types/lookup.go
@@ -67,24 +67,22 @@
 	}
 
 	typ, isPtr := deref(T)
-	named, _ := typ.(*Named)
 
 	// *typ where typ is an interface has no methods.
-	if isPtr {
-		utyp := typ
-		if named != nil {
-			utyp = named.underlying
-		}
-		if _, ok := utyp.(*Interface); ok {
-			return
-		}
+	if isPtr && IsInterface(typ) {
+		return
 	}
 
 	// Start with typ as single entry at shallowest depth.
-	// If typ is not a named type, insert a nil type instead.
-	current := []embeddedType{{named, nil, isPtr, false}}
+	current := []embeddedType{{typ, nil, isPtr, false}}
 
-	// named types that we have seen already, allocated lazily
+	// Named types that we have seen already, allocated lazily.
+	// Used to avoid endless searches in case of recursive types.
+	// Since only Named types can be used for recursive types, we
+	// only need to track those.
+	// (If we ever allow type aliases to construct recursive types,
+	// we must use type identity rather than pointer equality for
+	// the map key comparison, as we do in consolidateMultiples.)
 	var seen map[*Named]bool
 
 	// search current depth
@@ -93,11 +91,12 @@
 
 		// look for (pkg, name) in all types at current depth
 		for _, e := range current {
-			// The very first time only, e.typ may be nil.
-			// In this case, we don't have a named type and
-			// we simply continue with the underlying type.
-			if e.typ != nil {
-				if seen[e.typ] {
+			typ := e.typ
+
+			// If we have a named type, we may have associated methods.
+			// Look for those first.
+			if named, _ := typ.(*Named); named != nil {
+				if seen[named] {
 					// We have seen this type before, at a more shallow depth
 					// (note that multiples of this type at the current depth
 					// were consolidated before). The type at that depth shadows
@@ -108,10 +107,10 @@
 				if seen == nil {
 					seen = make(map[*Named]bool)
 				}
-				seen[e.typ] = true
+				seen[named] = true
 
 				// look for a matching attached method
-				if i, m := lookupMethod(e.typ.methods, pkg, name); m != nil {
+				if i, m := lookupMethod(named.methods, pkg, name); m != nil {
 					// potential match
 					assert(m.typ != nil)
 					index = concat(e.index, i)
@@ -124,7 +123,7 @@
 				}
 
 				// continue with underlying type
-				typ = e.typ.underlying
+				typ = named.underlying
 			}
 
 			switch t := typ.(type) {
@@ -147,16 +146,15 @@
 					// we have a name collision on the same depth; in either
 					// case we don't need to look further).
 					// Embedded fields are always of the form T or *T where
-					// T is a named type. If e.typ appeared multiple times at
+					// T is a type name. If e.typ appeared multiple times at
 					// this depth, f.typ appears multiple times at the next
 					// depth.
 					if obj == nil && f.anonymous {
-						// Ignore embedded basic types - only user-defined
-						// named types can have methods or struct fields.
 						typ, isPtr := deref(f.typ)
-						if t, _ := typ.(*Named); t != nil {
-							next = append(next, embeddedType{t, concat(e.index, i), e.indirect || isPtr, e.multiples})
-						}
+						// TODO(gri) optimization: ignore types that can't
+						// have fields or methods (only Named, Struct, and
+						// Interface types need to be considered).
+						next = append(next, embeddedType{typ, concat(e.index, i), e.indirect || isPtr, e.multiples})
 					}
 				}
 
@@ -193,12 +191,12 @@
 	return nil, nil, false // not found
 }
 
-// embeddedType represents an embedded named type
+// embeddedType represents an embedded type
 type embeddedType struct {
-	typ       *Named // nil means use the outer typ variable instead
-	index     []int  // embedded field indices, starting with index at depth 0
-	indirect  bool   // if set, there was a pointer indirection on the path to this field
-	multiples bool   // if set, typ appears multiple times at this depth
+	typ       Type
+	index     []int // embedded field indices, starting with index at depth 0
+	indirect  bool  // if set, there was a pointer indirection on the path to this field
+	multiples bool  // if set, typ appears multiple times at this depth
 }
 
 // consolidateMultiples collects multiple list entries with the same type
@@ -209,10 +207,10 @@
 		return list // at most one entry - nothing to do
 	}
 
-	n := 0                       // number of entries w/ unique type
-	prev := make(map[*Named]int) // index at which type was previously seen
+	n := 0                     // number of entries w/ unique type
+	prev := make(map[Type]int) // index at which type was previously seen
 	for _, e := range list {
-		if i, found := prev[e.typ]; found {
+		if i, found := lookupType(prev, e.typ); found {
 			list[i].multiples = true
 			// ignore this entry
 		} else {
@@ -224,6 +222,21 @@
 	return list[:n]
 }
 
+func lookupType(m map[Type]int, typ Type) (int, bool) {
+	// fast path: maybe the types are equal
+	if i, found := m[typ]; found {
+		return i, true
+	}
+
+	for t, i := range m {
+		if Identical(t, typ) {
+			return i, true
+		}
+	}
+
+	return 0, false
+}
+
 // MissingMethod returns (nil, false) if V implements T, otherwise it
 // returns a missing method required by T and whether it is missing or
 // just has the wrong type.
diff --git a/src/go/types/methodset.go b/src/go/types/methodset.go
index b27f2da..4f791d9 100644
--- a/src/go/types/methodset.go
+++ b/src/go/types/methodset.go
@@ -72,24 +72,22 @@
 	var base methodSet
 
 	typ, isPtr := deref(T)
-	named, _ := typ.(*Named)
 
 	// *typ where typ is an interface has no methods.
-	if isPtr {
-		utyp := typ
-		if named != nil {
-			utyp = named.underlying
-		}
-		if _, ok := utyp.(*Interface); ok {
-			return &emptyMethodSet
-		}
+	if isPtr && IsInterface(typ) {
+		return &emptyMethodSet
 	}
 
 	// Start with typ as single entry at shallowest depth.
-	// If typ is not a named type, insert a nil type instead.
-	current := []embeddedType{{named, nil, isPtr, false}}
+	current := []embeddedType{{typ, nil, isPtr, false}}
 
-	// named types that we have seen already, allocated lazily
+	// Named types that we have seen already, allocated lazily.
+	// Used to avoid endless searches in case of recursive types.
+	// Since only Named types can be used for recursive types, we
+	// only need to track those.
+	// (If we ever allow type aliases to construct recursive types,
+	// we must use type identity rather than pointer equality for
+	// the map key comparison, as we do in consolidateMultiples.)
 	var seen map[*Named]bool
 
 	// collect methods at current depth
@@ -101,11 +99,12 @@
 		var mset methodSet
 
 		for _, e := range current {
-			// The very first time only, e.typ may be nil.
-			// In this case, we don't have a named type and
-			// we simply continue with the underlying type.
-			if e.typ != nil {
-				if seen[e.typ] {
+			typ := e.typ
+
+			// If we have a named type, we may have associated methods.
+			// Look for those first.
+			if named, _ := typ.(*Named); named != nil {
+				if seen[named] {
 					// We have seen this type before, at a more shallow depth
 					// (note that multiples of this type at the current depth
 					// were consolidated before). The type at that depth shadows
@@ -116,12 +115,12 @@
 				if seen == nil {
 					seen = make(map[*Named]bool)
 				}
-				seen[e.typ] = true
+				seen[named] = true
 
-				mset = mset.add(e.typ.methods, e.index, e.indirect, e.multiples)
+				mset = mset.add(named.methods, e.index, e.indirect, e.multiples)
 
 				// continue with underlying type
-				typ = e.typ.underlying
+				typ = named.underlying
 			}
 
 			switch t := typ.(type) {
@@ -130,16 +129,15 @@
 					fset = fset.add(f, e.multiples)
 
 					// Embedded fields are always of the form T or *T where
-					// T is a named type. If typ appeared multiple times at
+					// T is a type name. If typ appeared multiple times at
 					// this depth, f.Type appears multiple times at the next
 					// depth.
 					if f.anonymous {
-						// Ignore embedded basic types - only user-defined
-						// named types can have methods or struct fields.
 						typ, isPtr := deref(f.typ)
-						if t, _ := typ.(*Named); t != nil {
-							next = append(next, embeddedType{t, concat(e.index, i), e.indirect || isPtr, e.multiples})
-						}
+						// TODO(gri) optimization: ignore types that can't
+						// have fields or methods (only Named, Struct, and
+						// Interface types need to be considered).
+						next = append(next, embeddedType{typ, concat(e.index, i), e.indirect || isPtr, e.multiples})
 					}
 				}
 
diff --git a/src/go/types/object.go b/src/go/types/object.go
index 6c0c5c4..3c44348 100644
--- a/src/go/types/object.go
+++ b/src/go/types/object.go
@@ -25,7 +25,7 @@
 	Name() string   // package local object name
 	Type() Type     // object type
 	Exported() bool // reports whether the name starts with a capital letter
-	Id() string     // object id (see Id below)
+	Id() string     // object name if exported, qualified name if not exported (see func Id)
 
 	// String returns a human-readable string of the object.
 	String() string
@@ -64,15 +64,10 @@
 	// inside a package and outside a package - which breaks some
 	// tests)
 	path := "_"
-	// TODO(gri): shouldn't !ast.IsExported(name) => pkg != nil be an precondition?
-	// if pkg == nil {
-	// 	panic("nil package in lookup of unexported name")
-	// }
-	if pkg != nil {
+	// pkg is nil for objects in Universe scope and possibly types
+	// introduced via Eval (see also comment in object.sameId)
+	if pkg != nil && pkg.path != "" {
 		path = pkg.path
-		if path == "" {
-			path = "_"
-		}
 	}
 	return path + "." + name
 }
@@ -154,7 +149,7 @@
 func (obj *Const) Val() constant.Value { return obj.val }
 func (*Const) isDependency()           {} // a constant may be a dependency of an initialization expression
 
-// A TypeName represents a declared type.
+// A TypeName represents a name for a (named or alias) type.
 type TypeName struct {
 	object
 }
@@ -163,6 +158,26 @@
 	return &TypeName{object{nil, pos, pkg, name, typ, 0, token.NoPos}}
 }
 
+// IsAlias reports whether obj is an alias name for a type.
+func (obj *TypeName) IsAlias() bool {
+	switch t := obj.typ.(type) {
+	case nil:
+		return false
+	case *Basic:
+		// Any user-defined type name for a basic type is an alias for a
+		// basic type (because basic types are pre-declared in the Universe
+		// scope, outside any package scope), and so is any type name with
+		// a different name than the name of the basic type it refers to.
+		// Additionaly, we need to look for "byte" and "rune" because they
+		// are aliases but have the same names (for better error messages).
+		return obj.pkg != nil || t.name != obj.name || t == universeByte || t == universeRune
+	case *Named:
+		return obj != t.obj
+	default:
+		return true
+	}
+}
+
 // A Variable represents a declared variable (including function parameters and results, and struct fields).
 type Var struct {
 	object
@@ -215,28 +230,6 @@
 func (obj *Func) Scope() *Scope { return obj.typ.(*Signature).scope }
 func (*Func) isDependency()     {} // a function may be a dependency of an initialization expression
 
-// An Alias represents a declared alias.
-type disabledAlias struct {
-	object
-	orig Object      // aliased constant, type, variable, or function; never an alias
-	kind token.Token // token.CONST, token.TYPE, token.VAR, or token.FUNC (only needed during resolve phase)
-}
-
-func disabledNewAlias(pos token.Pos, pkg *Package, name string, orig Object) *disabledAlias {
-	var typ Type = Typ[Invalid]
-	if orig != nil {
-		typ = orig.Type()
-	}
-	// No need to set a valid Alias.kind - that field is only used during identifier
-	// resolution (1st type-checker pass). We could store the field outside but it's
-	// easier to keep it here.
-	return &disabledAlias{object{nil, pos, pkg, name, typ, 0, token.NoPos}, orig, token.ILLEGAL}
-}
-
-// Orig returns the aliased object, or nil if there was an error.
-// The returned object is never an Alias.
-func (obj *disabledAlias) disabledOrig() Object { return obj.orig }
-
 // A Label represents a declared label.
 type Label struct {
 	object
@@ -264,7 +257,9 @@
 }
 
 func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
+	var tname *TypeName
 	typ := obj.Type()
+
 	switch obj := obj.(type) {
 	case *PkgName:
 		fmt.Fprintf(buf, "package %s", obj.Name())
@@ -277,8 +272,8 @@
 		buf.WriteString("const")
 
 	case *TypeName:
+		tname = obj
 		buf.WriteString("type")
-		typ = typ.Underlying()
 
 	case *Var:
 		if obj.isField {
@@ -295,10 +290,6 @@
 		}
 		return
 
-	// Alias-related code. Keep for now.
-	// case *Alias:
-	// 	buf.WriteString("alias")
-
 	case *Label:
 		buf.WriteString("label")
 		typ = nil
@@ -322,10 +313,27 @@
 		writePackage(buf, obj.Pkg(), qf)
 	}
 	buf.WriteString(obj.Name())
-	if typ != nil {
-		buf.WriteByte(' ')
-		WriteType(buf, typ, qf)
+
+	if typ == nil {
+		return
 	}
+
+	if tname != nil {
+		// We have a type object: Don't print anything more for
+		// basic types since there's no more information (names
+		// are the same; see also comment in TypeName.IsAlias).
+		if _, ok := typ.(*Basic); ok {
+			return
+		}
+		if tname.IsAlias() {
+			buf.WriteString(" =")
+		} else {
+			typ = typ.Underlying()
+		}
+	}
+
+	buf.WriteByte(' ')
+	WriteType(buf, typ, qf)
 }
 
 func writePackage(buf *bytes.Buffer, pkg *Package, qf Qualifier) {
@@ -353,15 +361,14 @@
 	return buf.String()
 }
 
-func (obj *PkgName) String() string       { return ObjectString(obj, nil) }
-func (obj *Const) String() string         { return ObjectString(obj, nil) }
-func (obj *TypeName) String() string      { return ObjectString(obj, nil) }
-func (obj *Var) String() string           { return ObjectString(obj, nil) }
-func (obj *Func) String() string          { return ObjectString(obj, nil) }
-func (obj *disabledAlias) String() string { return ObjectString(obj, nil) }
-func (obj *Label) String() string         { return ObjectString(obj, nil) }
-func (obj *Builtin) String() string       { return ObjectString(obj, nil) }
-func (obj *Nil) String() string           { return ObjectString(obj, nil) }
+func (obj *PkgName) String() string  { return ObjectString(obj, nil) }
+func (obj *Const) String() string    { return ObjectString(obj, nil) }
+func (obj *TypeName) String() string { return ObjectString(obj, nil) }
+func (obj *Var) String() string      { return ObjectString(obj, nil) }
+func (obj *Func) String() string     { return ObjectString(obj, nil) }
+func (obj *Label) String() string    { return ObjectString(obj, nil) }
+func (obj *Builtin) String() string  { return ObjectString(obj, nil) }
+func (obj *Nil) String() string      { return ObjectString(obj, nil) }
 
 func writeFuncName(buf *bytes.Buffer, f *Func, qf Qualifier) {
 	if f.typ != nil {
diff --git a/src/go/types/object_test.go b/src/go/types/object_test.go
new file mode 100644
index 0000000..16d7d5c
--- /dev/null
+++ b/src/go/types/object_test.go
@@ -0,0 +1,43 @@
+// Copyright 2016 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 types
+
+import "testing"
+
+func TestIsAlias(t *testing.T) {
+	check := func(obj *TypeName, want bool) {
+		if got := obj.IsAlias(); got != want {
+			t.Errorf("%v: got IsAlias = %v; want %v", obj, got, want)
+		}
+	}
+
+	// predeclared types
+	for _, name := range Universe.Names() {
+		if obj, _ := Universe.Lookup(name).(*TypeName); obj != nil {
+			check(obj, name == "byte" || name == "rune")
+		}
+	}
+
+	// various other types
+	pkg := NewPackage("p", "p")
+	t1 := NewTypeName(0, pkg, "t1", nil)
+	n1 := NewNamed(t1, new(Struct), nil)
+	for _, test := range []struct {
+		name  *TypeName
+		alias bool
+	}{
+		{NewTypeName(0, nil, "t0", nil), false}, // no type yet
+		{NewTypeName(0, pkg, "t0", nil), false}, // no type yet
+		{t1, false},                             // type name refers to named type and vice versa
+		{NewTypeName(0, nil, "t2", new(Interface)), true}, // type name refers to unnamed type
+		{NewTypeName(0, pkg, "t3", n1), true},             // type name refers to named type with different type name
+		{NewTypeName(0, nil, "t4", Typ[Int32]), true},     // type name refers to basic type with different name
+		{NewTypeName(0, nil, "int32", Typ[Int32]), false}, // type name refers to basic type with same name
+		{NewTypeName(0, pkg, "int32", Typ[Int32]), true},  // type name is declared in user-defined package (outside Universe)
+		{NewTypeName(0, nil, "rune", Typ[Rune]), true},    // type name refers to basic type rune which is an alias already
+	} {
+		check(test.name, test.alias)
+	}
+}
diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go
index 21fd81e..c3b87dd 100644
--- a/src/go/types/predicates.go
+++ b/src/go/types/predicates.go
@@ -139,7 +139,7 @@
 	case *Basic:
 		// Basic types are singletons except for the rune and byte
 		// aliases, thus we cannot solely rely on the x == y check
-		// above.
+		// above. See also comment in TypeName.IsAlias.
 		if y, ok := y.(*Basic); ok {
 			return x.kind == y.kind
 		}
diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go
index 046e147..939f70a 100644
--- a/src/go/types/resolver.go
+++ b/src/go/types/resolver.go
@@ -14,13 +14,14 @@
 	"unicode"
 )
 
-// A declInfo describes a package-level const, type, var, func, or alias declaration.
+// A declInfo describes a package-level const, type, var, or func declaration.
 type declInfo struct {
 	file  *Scope        // scope of file containing this declaration
 	lhs   []*Var        // lhs of n:1 variable declarations, or nil
 	typ   ast.Expr      // type, or nil
 	init  ast.Expr      // init/orig expression, or nil
 	fdecl *ast.FuncDecl // func declaration, or nil
+	alias bool          // type alias declaration
 
 	// The deps field tracks initialization expression dependencies.
 	// As a special (overloaded) case, it also tracks dependencies of
@@ -274,13 +275,6 @@
 							check.declare(fileScope, nil, obj, token.NoPos)
 						}
 
-					// Alias-related code. Keep for now.
-					// case *ast.AliasSpec:
-					// 	obj := NewAlias(s.Name.Pos(), pkg, s.Name.Name, nil)
-					// 	obj.typ = nil // unresolved
-					// 	obj.kind = d.Tok
-					// 	check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, init: s.Orig})
-
 					case *ast.ValueSpec:
 						switch d.Tok {
 						case token.CONST:
@@ -347,7 +341,7 @@
 
 					case *ast.TypeSpec:
 						obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
-						check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, typ: s.Type})
+						check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, typ: s.Type, alias: s.Assign.IsValid()})
 
 					default:
 						check.invalidAST(s.Pos(), "unknown ast.Spec node %T", s)
diff --git a/src/go/types/testdata/decls4.src b/src/go/types/testdata/decls4.src
new file mode 100644
index 0000000..5e5e2e9
--- /dev/null
+++ b/src/go/types/testdata/decls4.src
@@ -0,0 +1,150 @@
+// Copyright 2016 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.
+
+// type aliases
+
+package decls4
+
+type (
+	T0 [10]int
+	T1 []byte
+	T2 struct {
+		x int
+	}
+	T3 interface{
+		m() T2
+	}
+	T4 func(int, T0) chan T2
+)
+
+type (
+	Ai = int
+	A0 = T0
+	A1 = T1
+	A2 = T2
+	A3 = T3
+	A4 = T4
+
+	A10 = [10]int
+	A11 = []byte
+	A12 = struct {
+		x int
+	}
+	A13 = interface{
+		m() A2
+	}
+	A14 = func(int, A0) chan A2
+)
+
+// check assignment compatibility due to equality of types
+var (
+	xi_ int
+	ai Ai = xi_
+
+	x0 T0
+	a0 A0 = x0
+
+	x1 T1
+	a1 A1 = x1
+
+	x2 T2
+	a2 A2 = x2
+
+	x3 T3
+	a3 A3 = x3
+
+	x4 T4
+	a4 A4 = x4
+)
+
+// alias receiver types
+func (Ai /* ERROR "invalid receiver" */) m1() {}
+func (T0) m1() {}
+func (A0) m1 /* ERROR already declared */ () {}
+func (A0) m2 () {}
+func (A3 /* ERROR invalid receiver */ ) m1 () {}
+func (A10 /* ERROR invalid receiver */ ) m1() {}
+
+// x0 has methods m1, m2 declared via receiver type names T0 and A0
+var _ interface{ m1(); m2() } = x0
+
+// cycles
+type (
+	C2 /* ERROR illegal cycle */ = C2
+	C3 /* ERROR illegal cycle */ = C4
+	C4 = C3
+	C5 struct {
+		f *C6
+	}
+	C6 = C5
+	C7 /* ERROR illegal cycle */  struct {
+		f C8
+	}
+	C8 = C7
+)
+
+// embedded fields
+var (
+	s0 struct { T0 }
+	s1 struct { A0 } = s0 /* ERROR cannot use */ // embedded field names are different
+)
+
+// embedding and lookup of fields and methods
+func _(s struct{A0}) { s.A0 = x0 }
+
+type eX struct{xf int}
+
+func (eX) xm()
+
+type eY = struct{eX} // field/method set of eY includes xf, xm
+
+type eZ = *struct{eX} // field/method set of eZ includes xf, xm
+
+type eA struct {
+	eX // eX contributes xf, xm to eA
+}
+
+type eA2 struct {
+	*eX // *eX contributes xf, xm to eA
+}
+
+type eB struct {
+	eY // eY contributes xf, xm to eB
+}
+
+type eB2 struct {
+	*eY // *eY contributes xf, xm to eB
+}
+
+type eC struct {
+	eZ // eZ contributes xf, xm to eC
+}
+
+var (
+	_ = eA{}.xf
+	_ = eA{}.xm
+	_ = eA2{}.xf
+	_ = eA2{}.xm
+	_ = eB{}.xf
+	_ = eB{}.xm
+	_ = eB2{}.xf
+	_ = eB2{}.xm
+	_ = eC{}.xf
+	_ = eC{}.xm
+)
+
+// ambiguous selectors due to embedding via type aliases
+type eD struct {
+	eY
+	eZ
+}
+
+var (
+	_ = eD /* ERROR ambiguous selector */ {}.xf
+	_ = eD /* ERROR ambiguous selector */ {}.xm
+)
+
+var (
+	_ interface{ xm() } = eD /* ERROR missing method xm */ {}
+)
\ No newline at end of file
diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go
index 47378e7..0f8a7ad 100644
--- a/src/go/types/typestring.go
+++ b/src/go/types/typestring.go
@@ -56,6 +56,7 @@
 // This flag is exported in the x/tools/go/types package. We don't
 // need it at the moment in the std repo and so we don't export it
 // anymore. We should eventually try to remove it altogether.
+// TODO(gri) remove this
 var gcCompatibilityMode bool
 
 // TypeString returns the string representation of typ.
diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go
index ecc0a7d..1e906fc 100644
--- a/src/go/types/typexpr.go
+++ b/src/go/types/typexpr.go
@@ -45,17 +45,6 @@
 		delete(check.unusedDotImports[scope], pkg)
 	}
 
-	// Alias-related code. Keep for now.
-	// An alias stands for the original object; use that one instead.
-	// TODO(gri) We should be able to factor out the Typ[Invalid] test.
-	// if alias, _ := obj.(*Alias); alias != nil {
-	// 	obj = original(obj)
-	// 	if obj == nil || typ == Typ[Invalid] {
-	// 		return
-	// 	}
-	// 	assert(typ == obj.Type())
-	// }
-
 	switch obj := obj.(type) {
 	case *PkgName:
 		check.errorf(e.Pos(), "use of package %s not in selector", obj.name)
@@ -661,47 +650,41 @@
 			}
 		} else {
 			// anonymous field
-			name := anonymousFieldIdent(f.Type)
+			// spec: "An embedded type must be specified as a type name T or as a pointer
+			// to a non-interface type name *T, and T itself may not be a pointer type."
 			pos := f.Type.Pos()
+			name := anonymousFieldIdent(f.Type)
+			if name == nil {
+				check.invalidAST(pos, "anonymous field type %s has no name", f.Type)
+				continue
+			}
 			t, isPtr := deref(typ)
-			switch t := t.(type) {
+			// Because we have a name, typ must be of the form T or *T, where T is the name
+			// of a (named or alias) type, and t (= deref(typ)) must be the type of T.
+			switch t := t.Underlying().(type) {
 			case *Basic:
 				if t == Typ[Invalid] {
 					// error was reported before
 					continue
 				}
+
 				// unsafe.Pointer is treated like a regular pointer
 				if t.kind == UnsafePointer {
 					check.errorf(pos, "anonymous field type cannot be unsafe.Pointer")
 					continue
 				}
-				add(f, name, true, pos)
 
-			case *Named:
-				// spec: "An embedded type must be specified as a type name
-				// T or as a pointer to a non-interface type name *T, and T
-				// itself may not be a pointer type."
-				switch u := t.underlying.(type) {
-				case *Basic:
-					// unsafe.Pointer is treated like a regular pointer
-					if u.kind == UnsafePointer {
-						check.errorf(pos, "anonymous field type cannot be unsafe.Pointer")
-						continue
-					}
-				case *Pointer:
-					check.errorf(pos, "anonymous field type cannot be a pointer")
+			case *Pointer:
+				check.errorf(pos, "anonymous field type cannot be a pointer")
+				continue
+
+			case *Interface:
+				if isPtr {
+					check.errorf(pos, "anonymous field type cannot be a pointer to an interface")
 					continue
-				case *Interface:
-					if isPtr {
-						check.errorf(pos, "anonymous field type cannot be a pointer to an interface")
-						continue
-					}
 				}
-				add(f, name, true, pos)
-
-			default:
-				check.invalidAST(pos, "anonymous field type %s must be named", typ)
 			}
+			add(f, name, true, pos)
 		}
 	}
 
@@ -714,7 +697,10 @@
 	case *ast.Ident:
 		return e
 	case *ast.StarExpr:
-		return anonymousFieldIdent(e.X)
+		// *T is valid, but **T is not
+		if _, ok := e.X.(*ast.StarExpr); !ok {
+			return anonymousFieldIdent(e.X)
+		}
 	case *ast.SelectorExpr:
 		return e.Sel
 	}
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index 7f8c129..382ad6b 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -3731,7 +3731,7 @@
 
 func TestArrayOf(t *testing.T) {
 	// check construction and use of type not in binary
-	for _, table := range []struct {
+	tests := []struct {
 		n          int
 		value      func(i int) interface{}
 		comparable bool
@@ -3809,7 +3809,9 @@
 			comparable: true,
 			want:       "[{0 0} {1 1} {2 2} {3 3} {4 4} {5 5} {6 6} {7 7} {8 8} {9 9}]",
 		},
-	} {
+	}
+
+	for _, table := range tests {
 		at := ArrayOf(table.n, TypeOf(table.value(0)))
 		v := New(at).Elem()
 		vok := New(at).Elem()
@@ -4175,50 +4177,58 @@
 		f()
 	}
 
-	for i, test := range []struct {
+	tests := []struct {
 		field     StructField
 		mustPanic bool
 		exported  bool
 	}{
 		{
-			field:     StructField{Name: "", Type: TypeOf(S1{})},
-			mustPanic: false,
-			exported:  true,
+			field:    StructField{Name: "S1", Anonymous: true, Type: TypeOf(S1{})},
+			exported: true,
 		},
 		{
-			field:     StructField{Name: "", Type: TypeOf((*S1)(nil))},
-			mustPanic: false,
-			exported:  true,
+			field:    StructField{Name: "S1", Anonymous: true, Type: TypeOf((*S1)(nil))},
+			exported: true,
 		},
 		{
-			field:     StructField{Name: "", Type: TypeOf(s2{})},
-			mustPanic: false,
-			exported:  false,
-		},
-		{
-			field:     StructField{Name: "", Type: TypeOf((*s2)(nil))},
-			mustPanic: false,
-			exported:  false,
-		},
-		{
-			field:     StructField{Name: "", Type: TypeOf(S1{}), PkgPath: "other/pkg"},
+			field:     StructField{Name: "s2", Anonymous: true, Type: TypeOf(s2{})},
 			mustPanic: true,
-			exported:  true,
 		},
 		{
-			field:     StructField{Name: "", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"},
+			field:     StructField{Name: "s2", Anonymous: true, Type: TypeOf((*s2)(nil))},
 			mustPanic: true,
-			exported:  true,
 		},
 		{
-			field:     StructField{Name: "", Type: TypeOf(s2{}), PkgPath: "other/pkg"},
+			field:     StructField{Name: "Name", Type: nil, PkgPath: ""},
 			mustPanic: true,
-			exported:  false,
 		},
 		{
-			field:     StructField{Name: "", Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"},
+			field:     StructField{Name: "", Type: TypeOf(S1{}), PkgPath: ""},
 			mustPanic: true,
-			exported:  false,
+		},
+		{
+			field:     StructField{Name: "S1", Anonymous: true, Type: TypeOf(S1{}), PkgPath: "other/pkg"},
+			mustPanic: true,
+		},
+		{
+			field:     StructField{Name: "S1", Anonymous: true, Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"},
+			mustPanic: true,
+		},
+		{
+			field:     StructField{Name: "s2", Anonymous: true, Type: TypeOf(s2{}), PkgPath: "other/pkg"},
+			mustPanic: true,
+		},
+		{
+			field:     StructField{Name: "s2", Anonymous: true, Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"},
+			mustPanic: true,
+		},
+		{
+			field:     StructField{Name: "s2", Type: TypeOf(int(0)), PkgPath: "other/pkg"},
+			mustPanic: true,
+		},
+		{
+			field:     StructField{Name: "s2", Type: TypeOf(int(0)), PkgPath: "other/pkg"},
+			mustPanic: true,
 		},
 		{
 			field:     StructField{Name: "S", Type: TypeOf(S1{})},
@@ -4226,81 +4236,68 @@
 			exported:  true,
 		},
 		{
-			field:     StructField{Name: "S", Type: TypeOf((*S1)(nil))},
-			mustPanic: false,
-			exported:  true,
+			field:    StructField{Name: "S", Type: TypeOf((*S1)(nil))},
+			exported: true,
 		},
 		{
-			field:     StructField{Name: "S", Type: TypeOf(s2{})},
-			mustPanic: false,
-			exported:  true,
+			field:    StructField{Name: "S", Type: TypeOf(s2{})},
+			exported: true,
 		},
 		{
-			field:     StructField{Name: "S", Type: TypeOf((*s2)(nil))},
-			mustPanic: false,
-			exported:  true,
+			field:    StructField{Name: "S", Type: TypeOf((*s2)(nil))},
+			exported: true,
 		},
 		{
 			field:     StructField{Name: "s", Type: TypeOf(S1{})},
 			mustPanic: true,
-			exported:  false,
 		},
 		{
 			field:     StructField{Name: "s", Type: TypeOf((*S1)(nil))},
 			mustPanic: true,
-			exported:  false,
 		},
 		{
 			field:     StructField{Name: "s", Type: TypeOf(s2{})},
 			mustPanic: true,
-			exported:  false,
 		},
 		{
 			field:     StructField{Name: "s", Type: TypeOf((*s2)(nil))},
 			mustPanic: true,
-			exported:  false,
 		},
 		{
 			field:     StructField{Name: "s", Type: TypeOf(S1{}), PkgPath: "other/pkg"},
 			mustPanic: true, // TODO(sbinet): creating a name with a package path
-			exported:  false,
 		},
 		{
 			field:     StructField{Name: "s", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"},
 			mustPanic: true, // TODO(sbinet): creating a name with a package path
-			exported:  false,
 		},
 		{
 			field:     StructField{Name: "s", Type: TypeOf(s2{}), PkgPath: "other/pkg"},
 			mustPanic: true, // TODO(sbinet): creating a name with a package path
-			exported:  false,
 		},
 		{
 			field:     StructField{Name: "s", Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"},
 			mustPanic: true, // TODO(sbinet): creating a name with a package path
-			exported:  false,
 		},
 		{
 			field:     StructField{Name: "", Type: TypeOf(ΦType{})},
-			mustPanic: false,
-			exported:  true,
+			mustPanic: true,
 		},
 		{
 			field:     StructField{Name: "", Type: TypeOf(φType{})},
-			mustPanic: false,
-			exported:  false,
+			mustPanic: true,
 		},
 		{
-			field:     StructField{Name: "Φ", Type: TypeOf(0)},
-			mustPanic: false,
-			exported:  true,
+			field:    StructField{Name: "Φ", Type: TypeOf(0)},
+			exported: true,
 		},
 		{
-			field:     StructField{Name: "φ", Type: TypeOf(0)},
-			mustPanic: false,
-			exported:  false,
+			field:    StructField{Name: "φ", Type: TypeOf(0)},
+			exported: false,
 		},
-	} {
+	}
+
+	for i, test := range tests {
 		testPanic(i, test.mustPanic, func() {
 			typ := StructOf([]StructField{test.field})
 			if typ == nil {
@@ -4310,7 +4307,7 @@
 			field := typ.Field(0)
 			n := field.Name
 			if n == "" {
-				n = field.Type.Name()
+				panic("field.Name must not be empty")
 			}
 			exported := isExported(n)
 			if exported != test.exported {
@@ -4388,7 +4385,7 @@
 		{Name: "S1", Type: st1},
 	})
 
-	for _, table := range []struct {
+	tests := []struct {
 		rt  Type
 		idx []int
 	}{
@@ -4469,7 +4466,9 @@
 			),
 			idx: []int{2},
 		},
-	} {
+	}
+
+	for _, table := range tests {
 		v1 := New(table.rt).Elem()
 		v2 := New(table.rt).Elem()
 
@@ -4571,18 +4570,21 @@
 	type Iface interface {
 		Get() int
 	}
-	for i, table := range []struct {
+	tests := []struct {
+		name string
 		typ  Type
 		val  Value
 		impl bool
 	}{
 		{
+			name: "StructI",
 			typ:  TypeOf(StructI(want)),
 			val:  ValueOf(StructI(want)),
 			impl: true,
 		},
 		{
-			typ: PtrTo(TypeOf(StructI(want))),
+			name: "StructI",
+			typ:  PtrTo(TypeOf(StructI(want))),
 			val: ValueOf(func() interface{} {
 				v := StructI(want)
 				return &v
@@ -4590,7 +4592,8 @@
 			impl: true,
 		},
 		{
-			typ: PtrTo(TypeOf(StructIPtr(want))),
+			name: "StructIPtr",
+			typ:  PtrTo(TypeOf(StructIPtr(want))),
 			val: ValueOf(func() interface{} {
 				v := StructIPtr(want)
 				return &v
@@ -4598,6 +4601,7 @@
 			impl: true,
 		},
 		{
+			name: "StructIPtr",
 			typ:  TypeOf(StructIPtr(want)),
 			val:  ValueOf(StructIPtr(want)),
 			impl: false,
@@ -4607,13 +4611,16 @@
 		//	val:  ValueOf(StructI(want)),
 		//	impl: true,
 		// },
-	} {
+	}
+
+	for i, table := range tests {
 		rt := StructOf(
 			[]StructField{
 				{
-					Name:    "",
-					PkgPath: "",
-					Type:    table.typ,
+					Name:      table.name,
+					Anonymous: true,
+					PkgPath:   "",
+					Type:      table.typ,
 				},
 			},
 		)
@@ -6059,6 +6066,7 @@
 			want: []pairPtr{{5, 6, &c}, {3, 4, &b}, {1, 2, &a}},
 		},
 	}
+
 	for i, tt := range tests {
 		inStr := fmt.Sprint(tt.in)
 		Swapper(tt.in)(tt.i, tt.j)
@@ -6084,3 +6092,36 @@
 		lv.Set(rv)
 	})
 }
+
+type Tint int
+
+type Tint2 = Tint
+
+type Talias1 struct {
+	byte
+	uint8
+	int
+	int32
+	rune
+}
+
+type Talias2 struct {
+	Tint
+	Tint2
+}
+
+func TestAliasNames(t *testing.T) {
+	t1 := Talias1{byte: 1, uint8: 2, int: 3, int32: 4, rune: 5}
+	out := fmt.Sprintf("%#v", t1)
+	want := "reflect_test.Talias1{byte:0x1, uint8:0x2, int:3, int32:4, rune:5}"
+	if out != want {
+		t.Errorf("Talias1 print:\nhave: %s\nwant: %s", out, want)
+	}
+
+	t2 := Talias2{Tint: 1, Tint2: 2}
+	out = fmt.Sprintf("%#v", t2)
+	want = "reflect_test.Talias2{Tint:1, Tint2:2}"
+	if out != want {
+		t.Errorf("Talias2 print:\nhave: %s\nwant: %s", out, want)
+	}
+}
diff --git a/src/reflect/type.go b/src/reflect/type.go
index 5d3c5c6..4085909 100644
--- a/src/reflect/type.go
+++ b/src/reflect/type.go
@@ -417,9 +417,17 @@
 
 // Struct field
 type structField struct {
-	name   name    // name is empty for embedded fields
-	typ    *rtype  // type of field
-	offset uintptr // byte offset of field within struct
+	name       name    // name is always non-empty
+	typ        *rtype  // type of field
+	offsetAnon uintptr // byte offset of field<<1 | isAnonymous
+}
+
+func (f *structField) offset() uintptr {
+	return f.offsetAnon >> 1
+}
+
+func (f *structField) anon() bool {
+	return f.offsetAnon&1 != 0
 }
 
 // structType represents a struct type.
@@ -1215,16 +1223,8 @@
 	}
 	p := &t.fields[i]
 	f.Type = toType(p.typ)
-	if name := p.name.name(); name != "" {
-		f.Name = name
-	} else {
-		t := f.Type
-		if t.Kind() == Ptr {
-			t = t.Elem()
-		}
-		f.Name = t.Name()
-		f.Anonymous = true
-	}
+	f.Name = p.name.name()
+	f.Anonymous = p.anon()
 	if !p.name.isExported() {
 		f.PkgPath = p.name.pkgPath()
 		if f.PkgPath == "" {
@@ -1234,7 +1234,7 @@
 	if tag := p.name.tag(); tag != "" {
 		f.Tag = StructTag(tag)
 	}
-	f.Offset = p.offset
+	f.Offset = p.offset()
 
 	// NOTE(rsc): This is the only allocation in the interface
 	// presented by a reflect.Type. It would be nice to avoid,
@@ -1321,19 +1321,15 @@
 			visited[t] = true
 			for i := range t.fields {
 				f := &t.fields[i]
-				// Find name and type for field f.
-				var fname string
+				// Find name and (for anonymous field) type for field f.
+				fname := f.name.name()
 				var ntyp *rtype
-				if name := f.name.name(); name != "" {
-					fname = name
-				} else {
+				if f.anon() {
 					// Anonymous field of type T or *T.
-					// Name taken from type.
 					ntyp = f.typ
 					if ntyp.Kind() == Ptr {
 						ntyp = ntyp.Elem().common()
 					}
-					fname = ntyp.Name()
 				}
 
 				// Does it match?
@@ -1390,14 +1386,12 @@
 	if name != "" {
 		for i := range t.fields {
 			tf := &t.fields[i]
-			tfname := tf.name.name()
-			if tfname == "" {
-				hasAnon = true
-				continue
-			}
-			if tfname == name {
+			if tf.name.name() == name {
 				return t.Field(i), true
 			}
+			if tf.anon() {
+				hasAnon = true
+			}
 		}
 	}
 	if !hasAnon {
@@ -1695,7 +1689,7 @@
 			if cmpTags && tf.name.tag() != vf.name.tag() {
 				return false
 			}
-			if tf.offset != vf.offset {
+			if tf.offsetAnon != vf.offsetAnon {
 				return false
 			}
 			if !tf.name.isExported() {
@@ -2404,6 +2398,9 @@
 	lastzero := uintptr(0)
 	repr = append(repr, "struct {"...)
 	for i, field := range fields {
+		if field.Name == "" {
+			panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no name")
+		}
 		if field.Type == nil {
 			panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no type")
 		}
@@ -2416,13 +2413,11 @@
 			hasPtr = true
 		}
 
-		name := ""
 		// Update string and hash
-		if f.name.nameLen() > 0 {
-			hash = fnv1(hash, []byte(f.name.name())...)
-			repr = append(repr, (" " + f.name.name())...)
-			name = f.name.name()
-		} else {
+		name := f.name.name()
+		hash = fnv1(hash, []byte(name)...)
+		repr = append(repr, (" " + name)...)
+		if f.anon() {
 			// Embedded field
 			if f.typ.Kind() == Ptr {
 				// Embedded ** and *interface{} are illegal
@@ -2430,11 +2425,7 @@
 				if k := elem.Kind(); k == Ptr || k == Interface {
 					panic("reflect.StructOf: illegal anonymous field type " + ft.String())
 				}
-				name = elem.String()
-			} else {
-				name = ft.String()
 			}
-			// TODO(sbinet) check for syntactically impossible type names?
 
 			switch f.typ.Kind() {
 			case Interface:
@@ -2566,11 +2557,12 @@
 		comparable = comparable && (ft.alg.equal != nil)
 		hashable = hashable && (ft.alg.hash != nil)
 
-		f.offset = align(size, uintptr(ft.align))
+		offset := align(size, uintptr(ft.align))
 		if ft.align > typalign {
 			typalign = ft.align
 		}
-		size = f.offset + ft.size
+		size = offset + ft.size
+		f.offsetAnon |= offset << 1
 
 		if ft.size == 0 {
 			lastzero = size
@@ -2762,7 +2754,7 @@
 		typ.alg.hash = func(p unsafe.Pointer, seed uintptr) uintptr {
 			o := seed
 			for _, ft := range typ.fields {
-				pi := unsafe.Pointer(uintptr(p) + ft.offset)
+				pi := unsafe.Pointer(uintptr(p) + ft.offset())
 				o = ft.typ.alg.hash(pi, o)
 			}
 			return o
@@ -2772,8 +2764,8 @@
 	if comparable {
 		typ.alg.equal = func(p, q unsafe.Pointer) bool {
 			for _, ft := range typ.fields {
-				pi := unsafe.Pointer(uintptr(p) + ft.offset)
-				qi := unsafe.Pointer(uintptr(q) + ft.offset)
+				pi := unsafe.Pointer(uintptr(p) + ft.offset())
+				qi := unsafe.Pointer(uintptr(q) + ft.offset())
 				if !ft.typ.alg.equal(pi, qi) {
 					return false
 				}
@@ -2795,25 +2787,27 @@
 }
 
 func runtimeStructField(field StructField) structField {
-	exported := field.PkgPath == ""
-	if field.Name == "" {
-		t := field.Type.(*rtype)
-		if t.Kind() == Ptr {
-			t = t.Elem().(*rtype)
-		}
-		exported = t.nameOff(t.str).isExported()
-	} else if exported {
-		b0 := field.Name[0]
-		if ('a' <= b0 && b0 <= 'z') || b0 == '_' {
-			panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but has no PkgPath")
-		}
+	if field.PkgPath != "" {
+		panic("reflect.StructOf: StructOf does not allow unexported fields")
 	}
 
-	_ = resolveReflectType(field.Type.common())
+	// Best-effort check for misuse.
+	// Since PkgPath is empty, not much harm done if Unicode lowercase slips through.
+	c := field.Name[0]
+	if 'a' <= c && c <= 'z' || c == '_' {
+		panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but missing PkgPath")
+	}
+
+	offsetAnon := uintptr(0)
+	if field.Anonymous {
+		offsetAnon |= 1
+	}
+
+	resolveReflectType(field.Type.common()) // install in runtime
 	return structField{
-		name:   newName(field.Name, string(field.Tag), field.PkgPath, exported),
-		typ:    field.Type.common(),
-		offset: 0,
+		name:       newName(field.Name, string(field.Tag), "", true),
+		typ:        field.Type.common(),
+		offsetAnon: offsetAnon,
 	}
 }
 
@@ -2836,7 +2830,7 @@
 			}
 		}
 		f := st.fields[field]
-		return f.offset + f.typ.ptrdata
+		return f.offset() + f.typ.ptrdata
 
 	default:
 		panic("reflect.typeptrdata: unexpected type, " + t.String())
@@ -3210,7 +3204,7 @@
 		tt := (*structType)(unsafe.Pointer(t))
 		for i := range tt.fields {
 			f := &tt.fields[i]
-			addTypeBits(bv, offset+f.offset, f.typ)
+			addTypeBits(bv, offset+f.offset(), f.typ)
 		}
 	}
 }
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 387b9f3..125f04ea 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -769,7 +769,7 @@
 	fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind())
 	// Using an unexported field forces flagRO.
 	if !field.name.isExported() {
-		if field.name.name() == "" {
+		if field.anon() {
 			fl |= flagEmbedRO
 		} else {
 			fl |= flagStickyRO
@@ -780,7 +780,7 @@
 	// In the former case, we want v.ptr + offset.
 	// In the latter case, we must have field.offset = 0,
 	// so v.ptr + field.offset is still okay.
-	ptr := unsafe.Pointer(uintptr(v.ptr) + field.offset)
+	ptr := unsafe.Pointer(uintptr(v.ptr) + field.offset())
 	return Value{typ, ptr, fl}
 }
 
diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go
index 69e29ef..879e786 100644
--- a/src/runtime/cgocall.go
+++ b/src/runtime/cgocall.go
@@ -531,7 +531,7 @@
 			return
 		}
 		for _, f := range st.fields {
-			cgoCheckArg(f.typ, add(p, f.offset), true, top, msg)
+			cgoCheckArg(f.typ, add(p, f.offset()), true, top, msg)
 		}
 	case kindPtr, kindUnsafePointer:
 		if indir {
diff --git a/src/runtime/type.go b/src/runtime/type.go
index 3ecc54c..10442ef 100644
--- a/src/runtime/type.go
+++ b/src/runtime/type.go
@@ -390,9 +390,13 @@
 }
 
 type structfield struct {
-	name   name
-	typ    *_type
-	offset uintptr
+	name       name
+	typ        *_type
+	offsetAnon uintptr
+}
+
+func (f *structfield) offset() uintptr {
+	return f.offsetAnon >> 1
 }
 
 type structtype struct {
@@ -650,7 +654,7 @@
 			if tf.name.tag() != vf.name.tag() {
 				return false
 			}
-			if tf.offset != vf.offset {
+			if tf.offsetAnon != vf.offsetAnon {
 				return false
 			}
 		}
diff --git a/test/alias2.go b/test/alias2.go
new file mode 100644
index 0000000..32c3654
--- /dev/null
+++ b/test/alias2.go
@@ -0,0 +1,104 @@
+// errorcheck
+
+// Copyright 2016 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.
+
+// Test basic restrictions on type aliases.
+
+package p
+
+import (
+	"reflect"
+	. "reflect"
+)
+
+type T0 struct{}
+
+// Valid type alias declarations.
+
+type _ = T0
+type _ = int
+type _ = struct{}
+type _ = reflect.Value
+type _ = Value
+
+type (
+	A0 = T0
+	A1 = int
+	A2 = struct{}
+	A3 = reflect.Value
+	A4 = Value
+	A5 = Value
+
+	N0 A0
+)
+
+// Methods can be declared on the original named type and the alias.
+func (T0) m1()  {} // GCCGO_ERROR "previous"
+func (*T0) m1() {} // ERROR "method redeclared: T0\.m1|redefinition of .m1."
+func (A0) m1()  {} // ERROR "T0\.m1 redeclared in this block|redefinition of .m1."
+func (A0) m1()  {} // ERROR "T0\.m1 redeclared in this block|redefinition of .m1."
+func (A0) m2()  {}
+
+// Type aliases and the original type name can be used interchangeably.
+var _ A0 = T0{}
+var _ T0 = A0{}
+
+// But aliases and original types cannot be used with new types based on them.
+var _ N0 = T0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment|incompatible type"
+var _ N0 = A0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment|incompatible type"
+
+var _ A5 = Value{}
+
+var _ interface {
+	m1()
+	m2()
+} = T0{}
+
+var _ interface {
+	m1()
+	m2()
+} = A0{}
+
+func _() {
+	type _ = T0
+	type _ = int
+	type _ = struct{}
+	type _ = reflect.Value
+	type _ = Value
+
+	type (
+		A0 = T0
+		A1 = int
+		A2 = struct{}
+		A3 = reflect.Value
+		A4 = Value
+		A5 Value
+
+		N0 A0
+	)
+
+	var _ A0 = T0{}
+	var _ T0 = A0{}
+
+	var _ N0 = T0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment|incompatible type"
+	var _ N0 = A0{} // ERROR "cannot use T0 literal \(type T0\) as type N0 in assignment|incompatible type"
+
+	var _ A5 = Value{} // ERROR "cannot use reflect\.Value literal \(type reflect.Value\) as type A5 in assignment|incompatible type"
+}
+
+// Invalid type alias declarations.
+
+type _ = reflect.ValueOf // ERROR "reflect.ValueOf is not a type|expected type"
+
+func (A1) m() {} // ERROR "cannot define new methods on non-local type int|may not define methods on non-local type"
+func (A2) m() {} // ERROR "invalid receiver type"
+func (A3) m() {} // ERROR "cannot define new methods on non-local type reflect.Value|may not define methods on non-local type"
+func (A4) m() {} // ERROR "reflect.Value.m redeclared in this block" "cannot define new methods on non-local type reflect.Value|may not define methods on non-local type"
+
+type B1 = struct{}
+
+func (B1) m() {} // ERROR "m redeclared in this block" "invalid receiver type"
+
+// TODO(gri) expand
diff --git a/test/alias3.dir/a.go b/test/alias3.dir/a.go
new file mode 100644
index 0000000..09b3408
--- /dev/null
+++ b/test/alias3.dir/a.go
@@ -0,0 +1,42 @@
+// Copyright 2017 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 a
+
+import "go/build"
+
+type (
+	Float64 = float64
+	Rune    = rune
+)
+
+type (
+	Int       int
+	IntAlias  = Int
+	IntAlias2 = IntAlias
+	S         struct {
+		Int
+		IntAlias
+		IntAlias2
+	}
+)
+
+type (
+	Context = build.Context
+)
+
+type (
+	I1 interface {
+		M1(IntAlias2) Float64
+		M2() Context
+	}
+
+	I2 = interface {
+		M1(Int) float64
+		M2() build.Context
+	}
+)
+
+var i1 I1
+var i2 I2 = i1
diff --git a/test/alias3.dir/b.go b/test/alias3.dir/b.go
new file mode 100644
index 0000000..8a86cc0
--- /dev/null
+++ b/test/alias3.dir/b.go
@@ -0,0 +1,26 @@
+// Copyright 2017 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 b
+
+import (
+	"./a"
+	. "go/build"
+)
+
+func F(x float64) a.Float64 {
+	return x
+}
+
+type MyContext = Context // = build.Context
+
+var C a.Context = Default
+
+type S struct{}
+
+func (S) M1(x a.IntAlias) float64 { return a.Float64(x) }
+func (S) M2() Context             { return Default }
+
+var _ a.I1 = S{}
+var _ a.I2 = S{}
diff --git a/test/alias3.dir/c.go b/test/alias3.dir/c.go
new file mode 100644
index 0000000..161d593
--- /dev/null
+++ b/test/alias3.dir/c.go
@@ -0,0 +1,25 @@
+// Copyright 2017 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 main
+
+import (
+	"./a"
+	"./b"
+)
+
+func main() {
+	var _ float64 = b.F(0)
+	var _ a.Rune = int32(0)
+
+	// embedded types can have different names but the same types
+	var s a.S
+	s.Int = 1
+	s.IntAlias = s.Int
+	s.IntAlias2 = s.Int
+
+	// aliases denote identical types across packages
+	var c a.Context = b.C
+	var _ b.MyContext = c
+}
diff --git a/test/alias3.go b/test/alias3.go
new file mode 100644
index 0000000..c3732c3
--- /dev/null
+++ b/test/alias3.go
@@ -0,0 +1,7 @@
+// rundir
+
+// Copyright 2017 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 ignored
diff --git a/test/fixedbugs/issue18640.go b/test/fixedbugs/issue18640.go
new file mode 100644
index 0000000..c4f948b
--- /dev/null
+++ b/test/fixedbugs/issue18640.go
@@ -0,0 +1,26 @@
+// compile
+
+// Copyright 2017 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
+
+type (
+	a = b
+	b struct {
+		*a
+	}
+
+	c struct {
+		*d
+	}
+	d = c
+
+	e = f
+	f = g
+	g = []h
+	h i
+	i = j
+	j = e
+)
diff --git a/test/fixedbugs/issue18655.go b/test/fixedbugs/issue18655.go
new file mode 100644
index 0000000..abc2600
--- /dev/null
+++ b/test/fixedbugs/issue18655.go
@@ -0,0 +1,22 @@
+// errorcheck
+
+// Copyright 2017 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
+
+type T struct{}
+type A = T
+type B = T
+
+func (T) m() {}
+func (T) m() {} // ERROR "redeclared"
+func (A) m() {} // ERROR "redeclared"
+func (A) m() {} // ERROR "redeclared"
+func (B) m() {} // ERROR "redeclared"
+func (B) m() {} // ERROR "redeclared"
+
+func (*T) m() {} // ERROR "redeclared"
+func (*A) m() {} // ERROR "redeclared"
+func (*B) m() {} // ERROR "redeclared"