[dev.unified] all: merge master (635b124) into dev.unified

Merge List:

+ 2022-06-16 635b1244aa cmd/go: pass GOEXPERIMENT through to subtests
+ 2022-06-16 ef808ae1d4 expvar: don't crash if map value set to nil
+ 2022-06-16 32510eea74 go/parser: remove unused method checkBinaryExpr
+ 2022-06-16 74f1fa6ecb cmd/go: parallelize matchPackages work in each module
+ 2022-06-16 1d9d99b7ce cmd/link: consider alignment in carrier symbol size calculation
+ 2022-06-16 bcce8ef498 spec: adjust incorrect sentence in section on rune literals
+ 2022-06-16 ecc268aa26 test: add test that gofrontend fails
+ 2022-06-15 b6c1606889 internal/goarch, internal/goos: update generators for syslist.go
+ 2022-06-15 91baf5cecc reflect: fix reference comment to runtime/map.go
+ 2022-06-15 0e3d0c9581 syscall: clarify Pdeathsig documentation on Linux
+ 2022-06-15 74bf90c779 go/types, types2: add test case for issue for coverage
+ 2022-06-15 0cd0c12f57 doc/go1.19: use matching closing tag in unix build constraint heading
+ 2022-06-15 97bfc77f38 syscall, runtime/internal/syscall: always zero the higher bits of return value on linux/loong64
+ 2022-06-15 937fa5000a net/netip: add missing ) in ParsePrefix errors
+ 2022-06-15 c2c76c6f19 cmd/link: set alignment for carrier symbols
+ 2022-06-15 36147dd1e8 cmd/go/internal/modindex: disable indexing for modules outside GOROOT and the module cache
+ 2022-06-15 2a78e8afc0 test: add tests for string/[]byte/[]rune conversions
+ 2022-06-15 f9c0264107 net: avoid infinite recursion in Windows Resolver.lookupTXT
+ 2022-06-14 0dffda1383 spec: clarify "slice of bytes" and "slice of runes" through examples
+ 2022-06-14 c22a6c3b90 reflect: when StructOf overflows computing size/offset, panic
+ 2022-06-14 e1e66a03a6 cmd/compile,runtime,reflect: move embedded bit from offset to name
+ 2022-06-14 cb9bf93078 cmd/go: quote package directory when calling glob
+ 2022-06-14 cad477c922 cpu: fix typos in test case
+ 2022-06-13 c29be2d41c runtime: add HACKING section on nosplit functions
+ 2022-06-13 c5be77b687 doc/go1.19: minor edits
+ 2022-06-13 56bc3098f4 sync: improve linearity test robustness
+ 2022-06-13 1fe2810f9c sync: move lock linearity test and treat it like a performance test
+ 2022-06-13 6130461149 internal/testmath: add two-sample Welch's t-test for performance tests
+ 2022-06-13 24b9039149 doc/go1.19: prefer relative links to other parts of the Go website
+ 2022-06-13 fbc75dff2f cmd/cgo: remove -fsanitize=hwaddress hardware tags
+ 2022-06-13 5ee939b819 spec: clarify behavior of map size hint for make built-in
+ 2022-06-13 4703546a29 spec: add missing optional type arguments after TypeName in syntax
+ 2022-06-13 2c52465cb3 net: avoid darwin_arm64 bug in TestDialParallelSpuriousConnection
+ 2022-06-13 9228d7d7d5 doc/go1.19: add a release note for module indexing
+ 2022-06-13 7eeec1f6e4 cmd/compile: fix missing dict pass for type assertions
+ 2022-06-13 d27128b065 doc/go1.19: fix crypto tags
+ 2022-06-10 55590f3a2b net/http: doc: update RFC reference for appropriate HTTP codes
+ 2022-06-10 ff3db8d12d doc: fix typos in Go memory model
+ 2022-06-10 fb75c2da91 cmd/dist, cmd/internal/metadata: don't install metadata binary
+ 2022-06-10 386245b68e runtime: fix stack split at bad time when fuzzing
+ 2022-06-09 2cfbef4380 cmd/cgo: recognize clang 14 DWARF type names
+ 2022-06-09 c7ccabf3fe runtime/cgo: retry _beginthread on EACCES
+ 2022-06-09 91019cc13d runtime/cgo: merge bodies of cgo_sys_thread_start on windows
+ 2022-06-09 840e99ed74 api: promote next to go1.19
+ 2022-06-09 1a2ca95ad2 go/types, types2: only set instance context if packages match
+ 2022-06-08 b51d44c6dd cmd/go/testdata/script: fix skip on list_replace_absolute_windows
+ 2022-06-08 80f86f706d api/next: minor reformat
+ 2022-06-08 13f6be2833 runtime: use pidleget for faketime jump
+ 2022-06-08 1292176bc9 cmd/go: clean paths before using them form index functions
+ 2022-06-08 1858ea5d85 syscall: remove unused setgroups on linux/loong64
+ 2022-06-08 bdde41e3ba runtime: skip TestGdbBacktrace on gdb bug
+ 2022-06-08 432158b69a net: fix testHookDialTCP race
+ 2022-06-08 899f0a29c7 cmd/go: enable module index by default
+ 2022-06-08 f862280e30 cmd/go: properly call PackageModuleRoot to get modroot for index
+ 2022-06-08 d65166024f cmd/go: set Root and target fields for packages in GOPATH
+ 2022-06-08 4afb0b9e53 doc/go1.19: delete remaining TODOs
+ 2022-06-08 3426b7201d runtime: gofmt
+ 2022-06-08 f330a3a987 doc/go1.19: complete most remaining TODOs
+ 2022-06-08 2882786bf4 runtime: remove unused pipe and setNonblock on linux/loong64
+ 2022-06-08 decdd87bea doc/go1.19: mention riscv64 supported regabi
+ 2022-06-07 b72a6a7b86 os: document that Chdir affects fs.FS returned by DirFS with a relative path
+ 2022-06-07 30b929b1ef syscall: remove unused accept on linux/loong64
+ 2022-06-07 a7551fe245 net: use synthetic network in TestDialParallel
+ 2022-06-07 19d71acd97 doc/go1.19: document that the assembler requires -p
+ 2022-06-07 d151134851 doc/go1.19: document linker CL that switches DWARF compressed section format
+ 2022-06-07 3507805bcd go/types, types2: better error message for invalid use of constraint type
+ 2022-06-07 269bf7e855 go/types, types2: better error message if type is not in type set
+ 2022-06-07 d4fb93be87 go/types, types2: use | rather than ∪ when printing term lists
+ 2022-06-07 346698eea7 doc/go1.19: add release notes for net/http and net/url
+ 2022-06-07 7a82c6859f doc/go1.19: adjust runtime release notes
+ 2022-06-07 f3e051a184 runtime: document GOMEMLIMIT in environment variables section
+ 2022-06-07 ef2567c7dd doc/go1.19: document loong64 port
+ 2022-06-07 69bb7c6ef5 sync/atomic: clarify that 8-byte alignment of variables is due to escape
+ 2022-06-07 81033fbd8e doc/go1.19: some platforms are still on TSAN v2
+ 2022-06-07 0c3a0543c2 doc/go1.19: compiler section is complete, modulo TODOs
+ 2022-06-07 835a946137 doc/go1.19: minor edits
+ 2022-06-07 429a4041eb doc/go1.19: complete TODOs for go/types
+ 2022-06-07 d2630aa4b2 doc/go1.19: add various crypto release notes
+ 2022-06-07 77d9252ddf runtime: fix inline assembly trampoline for arm64
+ 2022-06-07 38607c5538 cmd/link: specify -Wl,-z params as documented
+ 2022-06-07 95b68e1e02 doc/go1.19: delete boringcrypto TODO
+ 2022-06-07 a79623b019 doc/go1.19: add more TODOs from updated relnote
+ 2022-06-06 acfff42802 doc/go1.19: add release notes for the soft memory limit and idle GC
+ 2022-06-06 a71ca3dfbd runtime, sync, sync/atomic: document happens-before guarantees
+ 2022-06-06 3651a6117e go/doc/comment: add heuristics for common badly formatted comments
+ 2022-06-06 4c08260c51 doc/go_mem: update revision date
+ 2022-06-06 7271a0a287 doc/go1.19: gc requires -p=importpath
+ 2022-06-06 c1e2ecbaf9 doc/go1.19: document Resolver.PreferGo
+ 2022-06-06 11195c60e6 cmd/go: use index to match packages in dependency modules
+ 2022-06-06 ea5d7cbc26 all: boringcrypto post-merge cleanup
+ 2022-06-06 6c7b223c2b go/doc/comment: do not turn ``` into “`
+ 2022-06-06 ce757e94e0 go/doc/comment: add doc comment
+ 2022-06-06 95547aee8c cmd/compile: cast riscv64 rewrite shifts to unsigned int
+ 2022-06-06 d43ddc1f3f strconv: fix typo in atof.go
+ 2022-06-06 2fa45a4fcd cmd/link/internal/loadpe: handle _main reference properly
+ 2022-06-06 fc97075949 go/types, types2: simplify implementation of validType (fix TODO)
+ 2022-06-06 07eca49055 go/types, types2: use type nest to detect type cycles (fix validType)
+ 2022-06-06 770146d5a8 doc/go1.19: add TODOs for changes to go/types
+ 2022-06-06 1b8ca75eaa runtime: fix breakpoint in ppc64x
+ 2022-06-06 9ce28b518d text/template/parse: fix data race on lexer initialization
+ 2022-06-06 47e34ca533 go/types, types2: ensure that named types never expand infinitely
+ 2022-06-06 02e69cfa96 go/types, types2: store Named instance information separately
+ 2022-06-06 1323b0e8f0 go/types, types2: eliminate methodList in favor of just using Named.mu
+ 2022-06-06 846f971daa go/types, types2: remove Named.once in favor of monotonic state
+ 2022-06-06 66cbf67345 cmd/buildid: reject rewriting legacy buildids
+ 2022-06-04 47f806ce81 strconv: clarify ParseFloat accepts Go syntax for float literals
+ 2022-06-04 2730c6af9f runtime: fix typo in libfuzzer_arm64.s
+ 2022-06-04 a32a592c8c database/sql/driver: fix typo in driver.go
+ 2022-06-04 0293c51bc5 regexp: avoid copying each instruction executed
+ 2022-06-04 865911424d doc: update Go memory model
+ 2022-06-04 fc66cae490 doc/go1.19: remove TODO about LimitedReader
+ 2022-06-04 f8a53df314 io: revert: add an Err field to LimitedReader
+ 2022-06-04 21f05284c7 cmd/go: index standard library packages

Change-Id: Ia7595c77a555fd2a0e7bb3b6b2cfbb745bd4947b
diff --git a/codereview.cfg b/codereview.cfg
index 77a74f1..d2e7917 100644
--- a/codereview.cfg
+++ b/codereview.cfg
@@ -1 +1,2 @@
-branch: master
+branch: dev.unified
+parent-branch: master
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 70f1a2f..a5a2d56 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -75,11 +75,6 @@
 
 	types.LocalPkg = types.NewPkg(base.Ctxt.Pkgpath, "")
 
-	// We won't know localpkg's height until after import
-	// processing. In the mean time, set to MaxPkgHeight to ensure
-	// height comparisons at least work until then.
-	types.LocalPkg.Height = types.MaxPkgHeight
-
 	// pseudo-package, for scoping
 	types.BuiltinPkg = types.NewPkg("go.builtin", "") // TODO(gri) name this package go.builtin?
 	types.BuiltinPkg.Prefix = "go.builtin"            // not go%2ebuiltin
diff --git a/src/cmd/compile/internal/noder/codes.go b/src/cmd/compile/internal/noder/codes.go
index 8f54a07..f7ad250 100644
--- a/src/cmd/compile/internal/noder/codes.go
+++ b/src/cmd/compile/internal/noder/codes.go
@@ -1,5 +1,3 @@
-// UNREVIEWED
-
 // Copyright 2021 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.
@@ -8,6 +6,7 @@
 
 import "internal/pkgbits"
 
+// A codeStmt distinguishes among statement encodings.
 type codeStmt int
 
 func (c codeStmt) Marker() pkgbits.SyncMarker { return pkgbits.SyncStmt1 }
@@ -31,6 +30,7 @@
 	stmtSelect
 )
 
+// A codeExpr distinguishes among expression encodings.
 type codeExpr int
 
 func (c codeExpr) Marker() pkgbits.SyncMarker { return pkgbits.SyncExpr }
@@ -38,12 +38,9 @@
 
 // TODO(mdempsky): Split expr into addr, for lvalues.
 const (
-	exprNone codeExpr = iota
-	exprConst
-	exprType  // type expression
-	exprLocal // local variable
-	exprName  // global variable or function
-	exprBlank
+	exprConst  codeExpr = iota
+	exprLocal           // local variable
+	exprGlobal          // global variable or function
 	exprCompLit
 	exprFuncLit
 	exprSelector
@@ -54,8 +51,22 @@
 	exprBinaryOp
 	exprCall
 	exprConvert
+	exprNew
+	exprMake
 )
 
+type codeAssign int
+
+func (c codeAssign) Marker() pkgbits.SyncMarker { return pkgbits.SyncAssign }
+func (c codeAssign) Value() int                 { return int(c) }
+
+const (
+	assignBlank codeAssign = iota
+	assignDef
+	assignExpr
+)
+
+// A codeDecl distinguishes among declaration encodings.
 type codeDecl int
 
 func (c codeDecl) Marker() pkgbits.SyncMarker { return pkgbits.SyncDecl }
diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go
index 33acd60..8efcef2 100644
--- a/src/cmd/compile/internal/noder/helpers.go
+++ b/src/cmd/compile/internal/noder/helpers.go
@@ -39,10 +39,6 @@
 
 // Values
 
-func Const(pos src.XPos, typ *types.Type, val constant.Value) ir.Node {
-	return typed(typ, ir.NewBasicLit(pos, val))
-}
-
 func OrigConst(pos src.XPos, typ *types.Type, val constant.Value, op ir.Op, raw string) ir.Node {
 	orig := ir.NewRawOrigExpr(pos, op, raw)
 	return ir.NewConstExpr(val, typed(typ, orig))
diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go
index 628c0f5..74e7401 100644
--- a/src/cmd/compile/internal/noder/irgen.go
+++ b/src/cmd/compile/internal/noder/irgen.go
@@ -219,7 +219,6 @@
 
 func (g *irgen) generate(noders []*noder) {
 	types.LocalPkg.Name = g.self.Name()
-	types.LocalPkg.Height = g.self.Height()
 	typecheck.TypecheckAllowed = true
 
 	// Prevent size calculations until we set the underlying type
diff --git a/src/cmd/compile/internal/noder/linker.go b/src/cmd/compile/internal/noder/linker.go
index a58b9b9..1626c04 100644
--- a/src/cmd/compile/internal/noder/linker.go
+++ b/src/cmd/compile/internal/noder/linker.go
@@ -1,5 +1,3 @@
-// UNREVIEWED
-
 // Copyright 2021 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.
@@ -34,6 +32,9 @@
 // low-level linking details can be moved there, but the logic for
 // handling extension data needs to stay in the compiler.
 
+// A linker combines a package's stub export data with any referenced
+// elements from imported packages into a single, self-contained
+// export data file.
 type linker struct {
 	pw pkgbits.PkgEncoder
 
@@ -41,6 +42,9 @@
 	decls map[*types.Sym]pkgbits.Index
 }
 
+// relocAll ensures that all elements specified by pr and relocs are
+// copied into the output export data file, and returns the
+// corresponding indices in the output.
 func (l *linker) relocAll(pr *pkgReader, relocs []pkgbits.RelocEnt) []pkgbits.RelocEnt {
 	res := make([]pkgbits.RelocEnt, len(relocs))
 	for i, rent := range relocs {
@@ -50,6 +54,8 @@
 	return res
 }
 
+// relocIdx ensures a single element is copied into the output export
+// data file, and returns the corresponding index in the output.
 func (l *linker) relocIdx(pr *pkgReader, k pkgbits.RelocKind, idx pkgbits.Index) pkgbits.Index {
 	assert(pr != nil)
 
@@ -85,10 +91,19 @@
 	return newidx
 }
 
+// relocString copies the specified string from pr into the output
+// export data file, deduplicating it against other strings.
 func (l *linker) relocString(pr *pkgReader, idx pkgbits.Index) pkgbits.Index {
 	return l.pw.StringIdx(pr.StringIdx(idx))
 }
 
+// relocPkg copies the specified package from pr into the output
+// export data file, rewriting its import path to match how it was
+// imported.
+//
+// TODO(mdempsky): Since CL 391014, we already have the compilation
+// unit's import path, so there should be no need to rewrite packages
+// anymore.
 func (l *linker) relocPkg(pr *pkgReader, idx pkgbits.Index) pkgbits.Index {
 	path := pr.PeekPkgPath(idx)
 
@@ -114,6 +129,9 @@
 	return w.Flush()
 }
 
+// relocObj copies the specified object from pr into the output export
+// data file, rewriting its compiler-private extension data (e.g.,
+// adding inlining cost and escape analysis results for functions).
 func (l *linker) relocObj(pr *pkgReader, idx pkgbits.Index) pkgbits.Index {
 	path, name, tag := pr.PeekObj(idx)
 	sym := types.NewPkg(path, "").Lookup(name)
@@ -184,6 +202,8 @@
 	return w.Idx
 }
 
+// relocCommon copies the specified element from pr into w,
+// recursively relocating any referenced elements as well.
 func (l *linker) relocCommon(pr *pkgReader, w *pkgbits.Encoder, k pkgbits.RelocKind, idx pkgbits.Index) {
 	r := pr.NewDecoderRaw(k, idx)
 	w.Relocs = l.relocAll(pr, r.Relocs)
diff --git a/src/cmd/compile/internal/noder/quirks.go b/src/cmd/compile/internal/noder/quirks.go
index c4cb9b9..a22577f 100644
--- a/src/cmd/compile/internal/noder/quirks.go
+++ b/src/cmd/compile/internal/noder/quirks.go
@@ -1,5 +1,3 @@
-// UNREVIEWED
-
 // Copyright 2021 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.
@@ -12,12 +10,12 @@
 	"cmd/compile/internal/syntax"
 )
 
-// This file defines helper functions useful for satisfying toolstash
-// -cmp when compared against the legacy frontend behavior, but can be
-// removed after that's no longer a concern.
-
 // typeExprEndPos returns the position that noder would leave base.Pos
 // after parsing the given type expression.
+//
+// Deprecated: This function exists to emulate position semantics from
+// Go 1.17, necessary for compatibility with the backend DWARF
+// generation logic that assigns variables to their appropriate scope.
 func typeExprEndPos(expr0 syntax.Expr) syntax.Pos {
 	for {
 		switch expr := expr0.(type) {
diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go
index 296cdd7..5ebc776 100644
--- a/src/cmd/compile/internal/noder/reader.go
+++ b/src/cmd/compile/internal/noder/reader.go
@@ -1,5 +1,3 @@
-// UNREVIEWED
-
 // Copyright 2021 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.
@@ -26,15 +24,25 @@
 	"cmd/internal/src"
 )
 
+// This file implements cmd/compile backend's reader for the Unified
+// IR export data.
+
+// A pkgReader reads Unified IR export data.
 type pkgReader struct {
 	pkgbits.PkgDecoder
 
+	// Indices for encoded things; lazily populated as needed.
+	//
+	// Note: Objects (i.e., ir.Names) are lazily instantiated by
+	// populating their types.Sym.Def; see objReader below.
+
 	posBases []*src.PosBase
 	pkgs     []*types.Pkg
 	typs     []*types.Type
 
-	// offset for rewriting the given index into the output,
-	// but bitwise inverted so we can detect if we're missing the entry or not.
+	// offset for rewriting the given (absolute!) index into the output,
+	// but bitwise inverted so we can detect if we're missing the entry
+	// or not.
 	newindex []pkgbits.Index
 }
 
@@ -50,6 +58,8 @@
 	}
 }
 
+// A pkgReaderIndex compactly identifies an index (and its
+// corresponding dictionary) within a package's export data.
 type pkgReaderIndex struct {
 	pr   *pkgReader
 	idx  pkgbits.Index
@@ -69,6 +79,7 @@
 	}
 }
 
+// A writer provides APIs for reading an individual element.
 type reader struct {
 	pkgbits.Decoder
 
@@ -162,6 +173,7 @@
 
 // @@@ Positions
 
+// pos reads a position from the bitstream.
 func (r *reader) pos() src.XPos {
 	return base.Ctxt.PosTable.XPos(r.pos0())
 }
@@ -178,10 +190,13 @@
 	return src.MakePos(posBase, line, col)
 }
 
+// posBase reads a position base from the bitstream.
 func (r *reader) posBase() *src.PosBase {
 	return r.inlPosBase(r.p.posBaseIdx(r.Reloc(pkgbits.RelocPosBase)))
 }
 
+// posBaseIdx returns the specified position base, reading it first if
+// needed.
 func (pr *pkgReader) posBaseIdx(idx pkgbits.Index) *src.PosBase {
 	if b := pr.posBases[idx]; b != nil {
 		return b
@@ -222,6 +237,7 @@
 	return b
 }
 
+// TODO(mdempsky): Document this.
 func (r *reader) inlPosBase(oldBase *src.PosBase) *src.PosBase {
 	if r.inlCall == nil {
 		return oldBase
@@ -236,36 +252,23 @@
 	return newBase
 }
 
+// TODO(mdempsky): Document this.
 func (r *reader) updatePos(xpos src.XPos) src.XPos {
 	pos := base.Ctxt.PosTable.Pos(xpos)
 	pos.SetBase(r.inlPosBase(pos.Base()))
 	return base.Ctxt.PosTable.XPos(pos)
 }
 
-func (r *reader) origPos(xpos src.XPos) src.XPos {
-	if r.inlCall == nil {
-		return xpos
-	}
-
-	pos := base.Ctxt.PosTable.Pos(xpos)
-	for old, new := range r.inlPosBases {
-		if pos.Base() == new {
-			pos.SetBase(old)
-			return base.Ctxt.PosTable.XPos(pos)
-		}
-	}
-
-	base.FatalfAt(xpos, "pos base missing from inlPosBases")
-	panic("unreachable")
-}
-
 // @@@ Packages
 
+// pkg reads a package reference from the bitstream.
 func (r *reader) pkg() *types.Pkg {
 	r.Sync(pkgbits.SyncPkg)
 	return r.p.pkgIdx(r.Reloc(pkgbits.RelocPkg))
 }
 
+// pkgIdx returns the specified package from the export data, reading
+// it first if needed.
 func (pr *pkgReader) pkgIdx(idx pkgbits.Index) *types.Pkg {
 	if pkg := pr.pkgs[idx]; pkg != nil {
 		return pkg
@@ -276,6 +279,7 @@
 	return pkg
 }
 
+// doPkg reads a package definition from the bitstream.
 func (r *reader) doPkg() *types.Pkg {
 	path := r.String()
 	switch path {
@@ -288,7 +292,7 @@
 	}
 
 	name := r.String()
-	height := r.Len()
+	_ = r.Len() // was package height, but not necessary anymore.
 
 	pkg := types.NewPkg(path, "")
 
@@ -298,12 +302,6 @@
 		base.Assertf(pkg.Name == name, "package %q has name %q, but want %q", pkg.Path, pkg.Name, name)
 	}
 
-	if pkg.Height == 0 {
-		pkg.Height = height
-	} else {
-		base.Assertf(pkg.Height == height, "package %q has height %v, but want %v", pkg.Path, pkg.Height, height)
-	}
-
 	return pkg
 }
 
@@ -536,8 +534,12 @@
 
 // @@@ Objects
 
+// objReader maps qualified identifiers (represented as *types.Sym) to
+// a pkgReader and corresponding index that can be used for reading
+// that object's definition.
 var objReader = map[*types.Sym]pkgReaderIndex{}
 
+// obj reads an instantiated object reference from the bitstream.
 func (r *reader) obj() ir.Node {
 	r.Sync(pkgbits.SyncObject)
 
@@ -573,6 +575,8 @@
 	return r.p.objIdx(idx, implicits, explicits)
 }
 
+// objIdx returns the specified object from the bitstream,
+// instantiated with the given type arguments, if any.
 func (pr *pkgReader) objIdx(idx pkgbits.Index, implicits, explicits []*types.Type) ir.Node {
 	rname := pr.newReader(pkgbits.RelocName, idx, pkgbits.SyncObject1)
 	_, sym := rname.qualifiedIdent()
@@ -605,6 +609,7 @@
 
 	do := func(op ir.Op, hasTParams bool) *ir.Name {
 		pos := r.pos()
+		setBasePos(pos)
 		if hasTParams {
 			r.typeParamNames()
 		}
@@ -712,6 +717,7 @@
 	return sym.Pkg.Lookup(buf.String())
 }
 
+// objDictIdx reads and returns the specified object dictionary.
 func (pr *pkgReader) objDictIdx(sym *types.Sym, idx pkgbits.Index, implicits, explicits []*types.Type) *readerDict {
 	r := pr.newReader(pkgbits.RelocObjDict, idx, pkgbits.SyncObject1)
 
@@ -960,6 +966,8 @@
 // constructed.
 var todoBodies []*ir.Func
 
+// addBody reads a function body reference from the element bitstream,
+// and associates it with fn.
 func (r *reader) addBody(fn *ir.Func) {
 	pri := pkgReaderIndex{r.p, r.Reloc(pkgbits.RelocBody), r.dict}
 	bodyReader[fn] = pri
@@ -983,6 +991,8 @@
 	r.funcBody(fn)
 }
 
+// funcBody reads a function body definition from the element
+// bitstream, and populates fn with it.
 func (r *reader) funcBody(fn *ir.Func) {
 	r.curfn = fn
 	r.closureVars = fn.ClosureVars
@@ -1230,10 +1240,8 @@
 	case stmtAssign:
 		pos := r.pos()
 
-		// TODO(mdempsky): After quirks mode is gone, swap these
-		// statements so we visit LHS before RHS again.
-		rhs := r.exprList()
 		names, lhs := r.assignList()
+		rhs := r.exprList()
 
 		if len(rhs) == 0 {
 			for _, name := range names {
@@ -1323,25 +1331,42 @@
 	var names []*ir.Name
 
 	for i := range lhs {
-		if r.Bool() {
-			pos := r.pos()
-			_, sym := r.localIdent()
-			typ := r.typ()
-
-			name := ir.NewNameAt(pos, sym)
-			lhs[i] = name
-			names = append(names, name)
-			setType(name, typ)
-			r.addLocal(name, ir.PAUTO)
-			continue
+		expr, def := r.assign()
+		lhs[i] = expr
+		if def {
+			names = append(names, expr.(*ir.Name))
 		}
-
-		lhs[i] = r.expr()
 	}
 
 	return names, lhs
 }
 
+// assign returns an assignee expression. It also reports whether the
+// returned expression is a newly declared variable.
+func (r *reader) assign() (ir.Node, bool) {
+	switch tag := codeAssign(r.Code(pkgbits.SyncAssign)); tag {
+	default:
+		panic("unhandled assignee expression")
+
+	case assignBlank:
+		return typecheck.AssignExpr(ir.BlankNode), false
+
+	case assignDef:
+		pos := r.pos()
+		setBasePos(pos)
+		_, sym := r.localIdent()
+		typ := r.typ()
+
+		name := ir.NewNameAt(pos, sym)
+		setType(name, typ)
+		r.addLocal(name, ir.PAUTO)
+		return name, true
+
+	case assignExpr:
+		return r.expr(), false
+	}
+}
+
 func (r *reader) blockStmt() []ir.Node {
 	r.Sync(pkgbits.SyncBlockStmt)
 	r.openScope()
@@ -1358,10 +1383,8 @@
 	if r.Bool() {
 		pos := r.pos()
 
-		// TODO(mdempsky): After quirks mode is gone, swap these
-		// statements so we read LHS before X again.
-		x := r.expr()
 		names, lhs := r.assignList()
+		x := r.expr()
 
 		body := r.blockStmt()
 		r.closeAnotherScope()
@@ -1380,7 +1403,7 @@
 
 	pos := r.pos()
 	init := r.stmt()
-	cond := r.expr()
+	cond := r.optExpr()
 	post := r.stmt()
 	body := r.blockStmt()
 	r.closeAnotherScope()
@@ -1450,7 +1473,7 @@
 		iface = x.Type()
 		tag = ir.NewTypeSwitchGuard(pos, ident, x)
 	} else {
-		tag = r.expr()
+		tag = r.optExpr()
 	}
 
 	clauses := make([]*ir.CaseClause, r.Len())
@@ -1551,25 +1574,14 @@
 	default:
 		panic("unhandled expression")
 
-	case exprNone:
-		return nil
-
-	case exprBlank:
-		// blank only allowed in LHS of assignments
-		// TODO(mdempsky): Handle directly in assignList instead?
-		return typecheck.AssignExpr(ir.BlankNode)
-
 	case exprLocal:
 		return typecheck.Expr(r.useLocal())
 
-	case exprName:
+	case exprGlobal:
 		// Callee instead of Expr allows builtins
 		// TODO(mdempsky): Handle builtins directly in exprCall, like method calls?
 		return typecheck.Callee(r.obj())
 
-	case exprType:
-		return r.exprType(false)
-
 	case exprConst:
 		pos := r.pos()
 		typ := r.typ()
@@ -1585,18 +1597,23 @@
 		return r.funcLit()
 
 	case exprSelector:
-		x := r.expr()
+		var x ir.Node
+		if r.Bool() { // MethodExpr
+			x = r.exprType(false)
+
+			// Method expression with derived receiver type.
+			if x.Op() == ir.ODYNAMICTYPE {
+				// TODO(mdempsky): Handle with runtime dictionary lookup.
+				n := ir.TypeNode(x.Type())
+				n.SetTypecheck(1)
+				x = n
+			}
+		} else { // FieldVal, MethodVal
+			x = r.expr()
+		}
 		pos := r.pos()
 		_, sym := r.selector()
 
-		// Method expression with derived receiver type.
-		if x.Op() == ir.ODYNAMICTYPE {
-			// TODO(mdempsky): Handle with runtime dictionary lookup.
-			n := ir.TypeNode(x.Type())
-			n.SetTypecheck(1)
-			x = n
-		}
-
 		n := typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, x, sym)).(*ir.SelectorExpr)
 		if n.Op() == ir.OMETHVALUE {
 			wrapper := methodValueWrapper{
@@ -1622,7 +1639,7 @@
 		pos := r.pos()
 		var index [3]ir.Node
 		for i := range index {
-			index[i] = r.expr()
+			index[i] = r.optExpr()
 		}
 		op := ir.OSLICE
 		if index[2] != nil {
@@ -1679,6 +1696,17 @@
 		dots := r.Bool()
 		return typecheck.Call(pos, fun, args, dots)
 
+	case exprMake:
+		pos := r.pos()
+		typ := r.exprType(false)
+		extra := r.exprs()
+		return typecheck.Expr(ir.NewCallExpr(pos, ir.OMAKE, nil, append([]ir.Node{typ}, extra...)))
+
+	case exprNew:
+		pos := r.pos()
+		typ := r.exprType(false)
+		return typecheck.Expr(ir.NewUnaryExpr(pos, ir.ONEW, typ))
+
 	case exprConvert:
 		typ := r.typ()
 		pos := r.pos()
@@ -1701,6 +1729,13 @@
 	}
 }
 
+func (r *reader) optExpr() ir.Node {
+	if r.Bool() {
+		return r.expr()
+	}
+	return nil
+}
+
 func (r *reader) compLit() ir.Node {
 	r.Sync(pkgbits.SyncCompLit)
 	pos := r.pos()
@@ -1807,6 +1842,7 @@
 	}
 
 	pos := r.pos()
+	setBasePos(pos)
 
 	lsymPtr := func(lsym *obj.LSym) ir.Node {
 		return typecheck.Expr(typecheck.NodAddr(ir.NewLinksymExpr(pos, lsym, types.Types[types.TUINT8])))
@@ -1974,6 +2010,8 @@
 
 var inlgen = 0
 
+// InlineCall implements inline.NewInline by re-reading the function
+// body from its Unified IR export data.
 func InlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExpr {
 	// TODO(mdempsky): Turn callerfn into an explicit parameter.
 	callerfn := ir.CurFunc
@@ -2260,18 +2298,21 @@
 	}
 }
 
+// importedDef reports whether r is reading from an imported and
+// non-generic element.
+//
+// If a type was found in an imported package, then we can assume that
+// package (or one of its transitive dependencies) already generated
+// method wrappers for it.
+//
+// Exception: If we're instantiating an imported generic type or
+// function, we might be instantiating it with type arguments not
+// previously seen before.
+//
+// TODO(mdempsky): Distinguish when a generic function or type was
+// instantiated in an imported package so that we can add types to
+// haveWrapperTypes instead.
 func (r *reader) importedDef() bool {
-	// If a type was found in an imported package, then we can assume
-	// that package (or one of its transitive dependencies) already
-	// generated method wrappers for it.
-	//
-	// Exception: If we're instantiating an imported generic type or
-	// function, we might be instantiating it with type arguments not
-	// previously seen before.
-	//
-	// TODO(mdempsky): Distinguish when a generic function or type was
-	// instantiated in an imported package so that we can add types to
-	// haveWrapperTypes instead.
 	return r.p != localPkgReader && !r.hasTypeParams()
 }
 
@@ -2459,6 +2500,15 @@
 	// so we're responsible for applying inlining ourselves here.
 	inline.InlineCalls(fn)
 
+	// The body of wrapper function after inlining may reveal new ir.OMETHVALUE node,
+	// we don't know whether wrapper function has been generated for it or not, so
+	// generate one immediately here.
+	ir.VisitList(fn.Body, func(n ir.Node) {
+		if n, ok := n.(*ir.SelectorExpr); ok && n.Op() == ir.OMETHVALUE {
+			wrapMethodValue(n.X.Type(), n.Selection, target, true)
+		}
+	})
+
 	target.Decls = append(target.Decls, fn)
 }
 
@@ -2516,3 +2566,8 @@
 	ret.Results = []ir.Node{call}
 	fn.Body.Append(ret)
 }
+
+func setBasePos(pos src.XPos) {
+	// Set the position for any error messages we might print (e.g. too large types).
+	base.Pos = pos
+}
diff --git a/src/cmd/compile/internal/noder/unified.go b/src/cmd/compile/internal/noder/unified.go
index 46acdab..95486af 100644
--- a/src/cmd/compile/internal/noder/unified.go
+++ b/src/cmd/compile/internal/noder/unified.go
@@ -1,5 +1,3 @@
-// UNREVIEWED
-
 // Copyright 2021 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.
@@ -82,7 +80,6 @@
 	base.Flag.Lang = fmt.Sprintf("go1.%d", goversion.Version)
 	types.ParseLangFlag()
 
-	types.LocalPkg.Height = 0 // reset so pkgReader.pkgIdx doesn't complain
 	target := typecheck.Target
 
 	typecheck.TypecheckAllowed = true
@@ -227,6 +224,8 @@
 	base.Fatalf("package never finalized")
 }
 
+// readPackage reads package export data from pr to populate
+// importpkg.
 func readPackage(pr *pkgReader, importpkg *types.Pkg) {
 	r := pr.newReader(pkgbits.RelocMeta, pkgbits.PublicRootIdx, pkgbits.SyncPublic)
 
@@ -253,6 +252,8 @@
 	}
 }
 
+// writeUnifiedExport writes to `out` the finalized, self-contained
+// Unified IR export data file for the current compilation unit.
 func writeUnifiedExport(out io.Writer) {
 	l := linker{
 		pw: pkgbits.NewPkgEncoder(base.Debug.SyncFrames),
diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go
index b440ad3..8ef63a0 100644
--- a/src/cmd/compile/internal/noder/writer.go
+++ b/src/cmd/compile/internal/noder/writer.go
@@ -1,5 +1,3 @@
-// UNREVIEWED
-
 // Copyright 2021 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.
@@ -16,6 +14,45 @@
 	"cmd/compile/internal/types2"
 )
 
+// This file implements the Unified IR package writer and defines the
+// Unified IR export data format.
+//
+// Low-level coding details (e.g., byte-encoding of individual
+// primitive values, or handling element bitstreams and
+// cross-references) are handled by internal/pkgbits, so here we only
+// concern ourselves with higher-level worries like mapping Go
+// language constructs into elements.
+
+// There are two central types in the writing process: the "writer"
+// type handles writing out individual elements, while the "pkgWriter"
+// type keeps track of which elements have already been created.
+//
+// For each sort of "thing" (e.g., position, package, object, type)
+// that can be written into the export data, there are generally
+// several methods that work together:
+//
+// - writer.thing handles writing out a *use* of a thing, which often
+//   means writing a relocation to that thing's encoded index.
+//
+// - pkgWriter.thingIdx handles reserving an index for a thing, and
+//   writing out any elements needed for the thing.
+//
+// - writer.doThing handles writing out the *definition* of a thing,
+//   which in general is a mix of low-level coding primitives (e.g.,
+//   ints and strings) or uses of other things.
+//
+// A design goal of Unified IR is to have a single, canonical writer
+// implementation, but multiple reader implementations each tailored
+// to their respective needs. For example, within cmd/compile's own
+// backend, inlining is implemented largely by just re-running the
+// function body reading code.
+
+// TODO(mdempsky): Add an importer for Unified IR to the x/tools repo,
+// and better document the file format boundary between public and
+// private data.
+
+// A pkgWriter constructs Unified IR export data from the results of
+// running the types2 type checker on a Go compilation unit.
 type pkgWriter struct {
 	pkgbits.PkgEncoder
 
@@ -23,18 +60,29 @@
 	curpkg *types2.Package
 	info   *types2.Info
 
+	// Indices for previously written syntax and types2 things.
+
 	posBasesIdx map[*syntax.PosBase]pkgbits.Index
 	pkgsIdx     map[*types2.Package]pkgbits.Index
 	typsIdx     map[types2.Type]pkgbits.Index
-	globalsIdx  map[types2.Object]pkgbits.Index
+	objsIdx     map[types2.Object]pkgbits.Index
+
+	// Maps from types2.Objects back to their syntax.Decl.
 
 	funDecls map[*types2.Func]*syntax.FuncDecl
 	typDecls map[*types2.TypeName]typeDeclGen
 
-	linknames  map[types2.Object]string
+	// linknames maps package-scope objects to their linker symbol name,
+	// if specified by a //go:linkname directive.
+	linknames map[types2.Object]string
+
+	// cgoPragmas accumulates any //go:cgo_* pragmas that need to be
+	// passed through to cmd/link.
 	cgoPragmas [][]string
 }
 
+// newPkgWriter returns an initialized pkgWriter for the specified
+// package.
 func newPkgWriter(m posMap, pkg *types2.Package, info *types2.Info) *pkgWriter {
 	return &pkgWriter{
 		PkgEncoder: pkgbits.NewPkgEncoder(base.Debug.SyncFrames),
@@ -43,9 +91,9 @@
 		curpkg: pkg,
 		info:   info,
 
-		pkgsIdx:    make(map[*types2.Package]pkgbits.Index),
-		globalsIdx: make(map[types2.Object]pkgbits.Index),
-		typsIdx:    make(map[types2.Type]pkgbits.Index),
+		pkgsIdx: make(map[*types2.Package]pkgbits.Index),
+		objsIdx: make(map[types2.Object]pkgbits.Index),
+		typsIdx: make(map[types2.Type]pkgbits.Index),
 
 		posBasesIdx: make(map[*syntax.PosBase]pkgbits.Index),
 
@@ -56,18 +104,23 @@
 	}
 }
 
+// errorf reports a user error about thing p.
 func (pw *pkgWriter) errorf(p poser, msg string, args ...interface{}) {
 	base.ErrorfAt(pw.m.pos(p), msg, args...)
 }
 
+// fatalf reports an internal compiler error about thing p.
 func (pw *pkgWriter) fatalf(p poser, msg string, args ...interface{}) {
 	base.FatalfAt(pw.m.pos(p), msg, args...)
 }
 
+// unexpected reports a fatal error about a thing of unexpected
+// dynamic type.
 func (pw *pkgWriter) unexpected(what string, p poser) {
 	pw.fatalf(p, "unexpected %s: %v (%T)", what, p, p)
 }
 
+// A writer provides APIs for writing out an individual element.
 type writer struct {
 	p *pkgWriter
 
@@ -77,13 +130,19 @@
 	// scope closes, and then maybe we can just use the same map for
 	// storing the TypeParams too (as their TypeName instead).
 
-	// variables declared within this function
+	// localsIdx tracks any local variables declared within this
+	// function body. It's unused for writing out non-body things.
 	localsIdx map[*types2.Var]int
 
-	closureVars    []posObj
-	closureVarsIdx map[*types2.Var]int
+	// closureVars tracks any free variables that are referenced by this
+	// function body. It's unused for writing out non-body things.
+	closureVars    []posVar
+	closureVarsIdx map[*types2.Var]int // index of previously seen free variables
 
-	dict    *writerDict
+	dict *writerDict
+
+	// derived tracks whether the type being written out references any
+	// type parameters. It's unused for writing non-type things.
 	derived bool
 }
 
@@ -128,16 +187,25 @@
 	derived bool
 }
 
+// An objInfo represents a reference to an encoded, instantiated (if
+// applicable) Go object.
 type objInfo struct {
 	idx       pkgbits.Index // index for the generic function declaration
 	explicits []typeInfo    // info for the type arguments
 }
 
+// An itabInfo represents a reference to an encoded itab entry (i.e.,
+// a non-empty interface type along with a concrete type that
+// implements that interface).
+//
+// itabInfo is only used for
 type itabInfo struct {
 	typIdx pkgbits.Index // always a derived type index
 	iface  typeInfo      // always a non-empty interface type
 }
 
+// anyDerived reports whether any of info's explicit type arguments
+// are derived types.
 func (info objInfo) anyDerived() bool {
 	for _, explicit := range info.explicits {
 		if explicit.derived {
@@ -147,6 +215,8 @@
 	return false
 }
 
+// equals reports whether info and other represent the same Go object
+// (i.e., same base object and identical type arguments, if any).
 func (info objInfo) equals(other objInfo) bool {
 	if info.idx != other.idx {
 		return false
@@ -169,6 +239,7 @@
 
 // @@@ Positions
 
+// pos writes the position of p into the element bitstream.
 func (w *writer) pos(p poser) {
 	w.Sync(pkgbits.SyncPos)
 	pos := p.Pos()
@@ -178,17 +249,19 @@
 		return
 	}
 
-	// TODO(mdempsky): Delta encoding. Also, if there's a b-side, update
-	// its position base too (but not vice versa!).
+	// TODO(mdempsky): Delta encoding.
 	w.posBase(pos.Base())
 	w.Uint(pos.Line())
 	w.Uint(pos.Col())
 }
 
+// posBase writes a reference to the given PosBase into the element
+// bitstream.
 func (w *writer) posBase(b *syntax.PosBase) {
 	w.Reloc(pkgbits.RelocPosBase, w.p.posBaseIdx(b))
 }
 
+// posBaseIdx returns the index for the given PosBase.
 func (pw *pkgWriter) posBaseIdx(b *syntax.PosBase) pkgbits.Index {
 	if idx, ok := pw.posBasesIdx[b]; ok {
 		return idx
@@ -210,11 +283,14 @@
 
 // @@@ Packages
 
+// pkg writes a use of the given Package into the element bitstream.
 func (w *writer) pkg(pkg *types2.Package) {
 	w.Sync(pkgbits.SyncPkg)
 	w.Reloc(pkgbits.RelocPkg, w.p.pkgIdx(pkg))
 }
 
+// pkgIdx returns the index for the given package, adding it to the
+// package export data if needed.
 func (pw *pkgWriter) pkgIdx(pkg *types2.Package) pkgbits.Index {
 	if idx, ok := pw.pkgsIdx[pkg]; ok {
 		return idx
@@ -241,7 +317,7 @@
 		base.Assertf(path != "builtin" && path != "unsafe", "unexpected path for user-defined package: %q", path)
 		w.String(path)
 		w.String(pkg.Name())
-		w.Len(pkg.Height())
+		w.Len(0) // was package height, but not necessary anymore.
 
 		w.Len(len(pkg.Imports()))
 		for _, imp := range pkg.Imports() {
@@ -256,10 +332,13 @@
 
 var anyTypeName = types2.Universe.Lookup("any").(*types2.TypeName)
 
+// typ writes a use of the given type into the bitstream.
 func (w *writer) typ(typ types2.Type) {
 	w.typInfo(w.p.typIdx(typ, w.dict))
 }
 
+// typInfo writes a use of the given type (specified as a typeInfo
+// instead) into the bitstream.
 func (w *writer) typInfo(info typeInfo) {
 	w.Sync(pkgbits.SyncType)
 	if w.Bool(info.derived) {
@@ -468,6 +547,11 @@
 
 // @@@ Objects
 
+// obj writes a use of the given object into the bitstream.
+//
+// If obj is a generic object, then explicits are the explicit type
+// arguments used to instantiate it (i.e., used to substitute the
+// object's own declared type parameters).
 func (w *writer) obj(obj types2.Object, explicits *types2.TypeList) {
 	explicitInfos := make([]typeInfo, explicits.Len())
 	for i := range explicitInfos {
@@ -515,8 +599,13 @@
 	}
 }
 
+// objIdx returns the index for the given Object, adding it to the
+// export data as needed.
 func (pw *pkgWriter) objIdx(obj types2.Object) pkgbits.Index {
-	if idx, ok := pw.globalsIdx[obj]; ok {
+	// TODO(mdempsky): Validate that obj is a global object (or a local
+	// defined type, which we hoist to global scope anyway).
+
+	if idx, ok := pw.objsIdx[obj]; ok {
 		return idx
 	}
 
@@ -530,12 +619,35 @@
 		dict.implicits = decl.implicits
 	}
 
+	// We encode objects into 4 elements across different sections, all
+	// sharing the same index:
+	//
+	// - RelocName has just the object's qualified name (i.e.,
+	//   Object.Pkg and Object.Name) and the CodeObj indicating what
+	//   specific type of Object it is (Var, Func, etc).
+	//
+	// - RelocObj has the remaining public details about the object,
+	//   relevant to go/types importers.
+	//
+	// - RelocObjExt has additional private details about the object,
+	//   which are only relevant to cmd/compile itself. This is
+	//   separated from RelocObj so that go/types importers are
+	//   unaffected by internal compiler changes.
+	//
+	// - RelocObjDict has public details about the object's type
+	//   parameters and derived type's used by the object. This is
+	//   separated to facilitate the eventual introduction of
+	//   shape-based stenciling.
+	//
+	// TODO(mdempsky): Re-evaluate whether RelocName still makes sense
+	// to keep separate from RelocObj.
+
 	w := pw.newWriter(pkgbits.RelocObj, pkgbits.SyncObject1)
 	wext := pw.newWriter(pkgbits.RelocObjExt, pkgbits.SyncObject1)
 	wname := pw.newWriter(pkgbits.RelocName, pkgbits.SyncObject1)
 	wdict := pw.newWriter(pkgbits.RelocObjDict, pkgbits.SyncObject1)
 
-	pw.globalsIdx[obj] = w.Idx // break cycles
+	pw.objsIdx[obj] = w.Idx // break cycles
 	assert(wext.Idx == w.Idx)
 	assert(wname.Idx == w.Idx)
 	assert(wdict.Idx == w.Idx)
@@ -557,6 +669,8 @@
 	return w.Idx
 }
 
+// doObj writes the RelocObj definition for obj to w, and the
+// RelocObjExt definition to wext.
 func (w *writer) doObj(wext *writer, obj types2.Object) pkgbits.CodeObj {
 	if obj.Pkg() != w.p.curpkg {
 		return pkgbits.ObjStub
@@ -619,6 +733,8 @@
 }
 
 // typExpr writes the type represented by the given expression.
+//
+// TODO(mdempsky): Document how this differs from exprType.
 func (w *writer) typExpr(expr syntax.Expr) {
 	tv, ok := w.p.info.Types[expr]
 	assert(ok)
@@ -724,8 +840,8 @@
 // me a little nervous to try it again.
 
 // localIdent writes the name of a locally declared object (i.e.,
-// objects that can only be accessed by name, within the context of a
-// particular function).
+// objects that can only be accessed by non-qualified name, within the
+// context of a particular function).
 func (w *writer) localIdent(obj types2.Object) {
 	assert(!isGlobal(obj))
 	w.Sync(pkgbits.SyncLocalIdent)
@@ -787,7 +903,7 @@
 	}
 
 	sig, block := obj.Type().(*types2.Signature), decl.Body
-	body, closureVars := w.p.bodyIdx(w.p.curpkg, sig, block, w.dict)
+	body, closureVars := w.p.bodyIdx(sig, block, w.dict)
 	assert(len(closureVars) == 0)
 
 	w.Sync(pkgbits.SyncFuncExt)
@@ -829,7 +945,9 @@
 
 // @@@ Function bodies
 
-func (pw *pkgWriter) bodyIdx(pkg *types2.Package, sig *types2.Signature, block *syntax.BlockStmt, dict *writerDict) (idx pkgbits.Index, closureVars []posObj) {
+// bodyIdx returns the index for the given function body (specified by
+// block), adding it to the export data
+func (pw *pkgWriter) bodyIdx(sig *types2.Signature, block *syntax.BlockStmt, dict *writerDict) (idx pkgbits.Index, closureVars []posVar) {
 	w := pw.newWriter(pkgbits.RelocBody, pkgbits.SyncFuncBody)
 	w.dict = dict
 
@@ -862,6 +980,7 @@
 	}
 }
 
+// addLocal records the declaration of a new local variable.
 func (w *writer) addLocal(obj *types2.Var) {
 	w.Sync(pkgbits.SyncAddLocal)
 	idx := len(w.localsIdx)
@@ -874,6 +993,8 @@
 	w.localsIdx[obj] = idx
 }
 
+// useLocal writes a reference to the given local or free variable
+// into the bitstream.
 func (w *writer) useLocal(pos syntax.Pos, obj *types2.Var) {
 	w.Sync(pkgbits.SyncUseObjLocal)
 
@@ -888,7 +1009,7 @@
 			w.closureVarsIdx = make(map[*types2.Var]int)
 		}
 		idx = len(w.closureVars)
-		w.closureVars = append(w.closureVars, posObj{pos, obj})
+		w.closureVars = append(w.closureVars, posVar{pos, obj})
 		w.closureVarsIdx[obj] = idx
 	}
 	w.Len(idx)
@@ -911,6 +1032,7 @@
 
 // @@@ Statements
 
+// stmt writes the given statement into the function body bitstream.
 func (w *writer) stmt(stmt syntax.Stmt) {
 	var stmts []syntax.Stmt
 	if stmt != nil {
@@ -954,8 +1076,8 @@
 		default:
 			w.Code(stmtAssign)
 			w.pos(stmt)
-			w.exprList(stmt.Rhs)
 			w.assignList(stmt.Lhs)
+			w.exprList(stmt.Rhs)
 		}
 
 	case *syntax.BlockStmt:
@@ -1023,25 +1145,36 @@
 	w.Len(len(exprs))
 
 	for _, expr := range exprs {
-		if name, ok := expr.(*syntax.Name); ok && name.Value != "_" {
-			if obj, ok := w.p.info.Defs[name]; ok {
-				obj := obj.(*types2.Var)
+		w.assign(expr)
+	}
+}
 
-				w.Bool(true)
-				w.pos(obj)
-				w.localIdent(obj)
-				w.typ(obj.Type())
+func (w *writer) assign(expr syntax.Expr) {
+	expr = unparen(expr)
 
-				// TODO(mdempsky): Minimize locals index size by deferring
-				// this until the variables actually come into scope.
-				w.addLocal(obj)
-				continue
-			}
+	if name, ok := expr.(*syntax.Name); ok {
+		if name.Value == "_" {
+			w.Code(assignBlank)
+			return
 		}
 
-		w.Bool(false)
-		w.expr(expr)
+		if obj, ok := w.p.info.Defs[name]; ok {
+			obj := obj.(*types2.Var)
+
+			w.Code(assignDef)
+			w.pos(obj)
+			w.localIdent(obj)
+			w.typ(obj.Type())
+
+			// TODO(mdempsky): Minimize locals index size by deferring
+			// this until the variables actually come into scope.
+			w.addLocal(obj)
+			return
+		}
 	}
+
+	w.Code(assignExpr)
+	w.expr(expr)
 }
 
 func (w *writer) declStmt(decl syntax.Decl) {
@@ -1054,8 +1187,8 @@
 	case *syntax.VarDecl:
 		w.Code(stmtAssign)
 		w.pos(decl)
-		w.exprList(decl.Values)
 		w.assignList(namesAsExpr(decl.NameList))
+		w.exprList(decl.Values)
 	}
 }
 
@@ -1072,12 +1205,12 @@
 
 	if rang, ok := stmt.Init.(*syntax.RangeClause); w.Bool(ok) {
 		w.pos(rang)
-		w.expr(rang.X)
 		w.assignList(rang.Lhs)
+		w.expr(rang.X)
 	} else {
 		w.pos(stmt)
 		w.stmt(stmt.Init)
-		w.expr(stmt.Cond)
+		w.optExpr(stmt.Cond)
 		w.stmt(stmt.Post)
 	}
 
@@ -1136,7 +1269,7 @@
 		}
 		w.expr(guard.X)
 	} else {
-		w.expr(stmt.Tag)
+		w.optExpr(stmt.Tag)
 	}
 
 	w.Len(len(stmt.Body))
@@ -1200,7 +1333,10 @@
 
 // @@@ Expressions
 
+// expr writes the given expression into the function body bitstream.
 func (w *writer) expr(expr syntax.Expr) {
+	base.Assertf(expr != nil, "missing expression")
+
 	expr = unparen(expr) // skip parens; unneeded after typecheck
 
 	obj, inst := lookupObj(w.p.info, expr)
@@ -1215,9 +1351,7 @@
 		}
 
 		if tv.IsType() {
-			w.Code(exprType)
-			w.exprType(nil, expr, false)
-			return
+			w.p.fatalf(expr, "unexpected type expression %v", syntax.String(expr))
 		}
 
 		if tv.Value != nil {
@@ -1236,7 +1370,7 @@
 
 	if obj != nil {
 		if isGlobal(obj) {
-			w.Code(exprName)
+			w.Code(exprGlobal)
 			w.obj(obj, targs)
 			return
 		}
@@ -1254,13 +1388,6 @@
 	default:
 		w.p.unexpected("expression", expr)
 
-	case nil: // absent slice index, for condition, or switch tag
-		w.Code(exprNone)
-
-	case *syntax.Name:
-		assert(expr.Value == "_")
-		w.Code(exprBlank)
-
 	case *syntax.CompositeLit:
 		w.Code(exprCompLit)
 		w.compLit(expr)
@@ -1274,7 +1401,11 @@
 		assert(ok)
 
 		w.Code(exprSelector)
-		w.expr(expr.X)
+		if w.Bool(sel.Kind() == types2.MethodExpr) {
+			w.exprType(nil, expr.X, false)
+		} else {
+			w.expr(expr.X)
+		}
 		w.pos(expr)
 		w.selector(sel.Obj())
 
@@ -1292,7 +1423,7 @@
 		w.expr(expr.X)
 		w.pos(expr)
 		for _, n := range &expr.Index {
-			w.expr(n)
+			w.optExpr(n)
 		}
 
 	case *syntax.AssertExpr:
@@ -1333,6 +1464,29 @@
 			break
 		}
 
+		if name, ok := unparen(expr.Fun).(*syntax.Name); ok && tv.IsBuiltin() {
+			switch name.Value {
+			case "make":
+				assert(len(expr.ArgList) >= 1)
+				assert(!expr.HasDots)
+
+				w.Code(exprMake)
+				w.pos(expr)
+				w.exprType(nil, expr.ArgList[0], false)
+				w.exprs(expr.ArgList[1:])
+				return
+
+			case "new":
+				assert(len(expr.ArgList) == 1)
+				assert(!expr.HasDots)
+
+				w.Code(exprNew)
+				w.pos(expr)
+				w.exprType(nil, expr.ArgList[0], false)
+				return
+			}
+		}
+
 		writeFunExpr := func() {
 			if selector, ok := unparen(expr.Fun).(*syntax.SelectorExpr); ok {
 				if sel, ok := w.p.info.Selections[selector]; ok && sel.Kind() == types2.MethodVal {
@@ -1356,6 +1510,12 @@
 	}
 }
 
+func (w *writer) optExpr(expr syntax.Expr) {
+	if w.Bool(expr != nil) {
+		w.expr(expr)
+	}
+}
+
 func (w *writer) compLit(lit *syntax.CompositeLit) {
 	tv, ok := w.p.info.Types[lit]
 	assert(ok)
@@ -1400,7 +1560,7 @@
 	assert(ok)
 	sig := tv.Type.(*types2.Signature)
 
-	body, closureVars := w.p.bodyIdx(w.p.curpkg, sig, expr.Body, w.dict)
+	body, closureVars := w.p.bodyIdx(sig, expr.Body, w.dict)
 
 	w.Sync(pkgbits.SyncFuncLit)
 	w.pos(expr)
@@ -1409,15 +1569,15 @@
 	w.Len(len(closureVars))
 	for _, cv := range closureVars {
 		w.pos(cv.pos)
-		w.useLocal(cv.pos, cv.obj)
+		w.useLocal(cv.pos, cv.var_)
 	}
 
 	w.Reloc(pkgbits.RelocBody, body)
 }
 
-type posObj struct {
-	pos syntax.Pos
-	obj *types2.Var
+type posVar struct {
+	pos  syntax.Pos
+	var_ *types2.Var
 }
 
 func (w *writer) exprList(expr syntax.Expr) {
@@ -1426,10 +1586,6 @@
 }
 
 func (w *writer) exprs(exprs []syntax.Expr) {
-	if len(exprs) == 0 {
-		assert(exprs == nil)
-	}
-
 	w.Sync(pkgbits.SyncExprs)
 	w.Len(len(exprs))
 	for _, expr := range exprs {
@@ -1474,6 +1630,9 @@
 	w.typInfo(info)
 }
 
+// isInterface reports whether typ is known to be an interface type.
+// If typ is a type parameter, then isInterface reports an internal
+// compiler error instead.
 func isInterface(typ types2.Type) bool {
 	if _, ok := typ.(*types2.TypeParam); ok {
 		// typ is a type parameter and may be instantiated as either a
@@ -1486,6 +1645,7 @@
 	return ok
 }
 
+// op writes an Op into the bitstream.
 func (w *writer) op(op ir.Op) {
 	// TODO(mdempsky): Remove in favor of explicit codes? Would make
 	// export data more stable against internal refactorings, but low
@@ -1526,6 +1686,12 @@
 	importedEmbed, importedUnsafe bool
 }
 
+// declCollector is a visitor type that collects compiler-needed
+// information about declarations that types2 doesn't track.
+//
+// Notably, it maps declared types and functions back to their
+// declaration statement, keeps track of implicit type parameters, and
+// assigns unique type "generation" numbers to local defined types.
 type declCollector struct {
 	pw         *pkgWriter
 	typegen    *int
@@ -1649,10 +1815,7 @@
 				}
 
 			default:
-				// TODO(mdempsky): Enable after #42938 is fixed.
-				if false {
-					pw.errorf(l.pos, "//go:linkname must refer to declared function or variable")
-				}
+				pw.errorf(l.pos, "//go:linkname must refer to declared function or variable")
 			}
 		}
 	}
diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go
index d5c4b8e..43ec7b8 100644
--- a/src/cmd/compile/internal/typecheck/iexport.go
+++ b/src/cmd/compile/internal/typecheck/iexport.go
@@ -405,7 +405,7 @@
 		w.string(exportPath(pkg))
 		if mainIndex {
 			w.string(pkg.Name)
-			w.uint64(uint64(pkg.Height))
+			w.uint64(0) // was package height, but not necessary anymore.
 		}
 
 		// Sort symbols within a package by name.
@@ -1978,6 +1978,7 @@
 		w.pos(n.Pos())
 		w.typ(n.Type())
 		w.expr(n.X)
+		w.bool(n.Implicit())
 
 	case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC:
 		n := n.(*ir.UnaryExpr)
diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go
index 3a51f78..96aaac6 100644
--- a/src/cmd/compile/internal/typecheck/iimport.go
+++ b/src/cmd/compile/internal/typecheck/iimport.go
@@ -175,10 +175,9 @@
 	for nPkgs := ird.uint64(); nPkgs > 0; nPkgs-- {
 		pkg := p.pkgAt(ird.uint64())
 		pkgName := p.stringAt(ird.uint64())
-		pkgHeight := int(ird.uint64())
+		_ = int(ird.uint64()) // was package height, but not necessary anymore.
 		if pkg.Name == "" {
 			pkg.Name = pkgName
-			pkg.Height = pkgHeight
 			types.NumImport[pkgName]++
 
 			// TODO(mdempsky): This belongs somewhere else.
@@ -187,9 +186,6 @@
 			if pkg.Name != pkgName {
 				base.Fatalf("conflicting package names %v and %v for path %q", pkg.Name, pkgName, pkg.Path)
 			}
-			if pkg.Height != pkgHeight {
-				base.Fatalf("conflicting package heights %v and %v for path %q", pkg.Height, pkgHeight, pkg.Path)
-			}
 		}
 
 		for nSyms := ird.uint64(); nSyms > 0; nSyms-- {
@@ -1493,7 +1489,9 @@
 		return n
 
 	case ir.OCONV, ir.OCONVIFACE, ir.OCONVIDATA, ir.OCONVNOP, ir.OBYTES2STR, ir.ORUNES2STR, ir.OSTR2BYTES, ir.OSTR2RUNES, ir.ORUNESTR, ir.OSLICE2ARRPTR:
-		return ir.NewConvExpr(r.pos(), op, r.typ(), r.expr())
+		n := ir.NewConvExpr(r.pos(), op, r.typ(), r.expr())
+		n.SetImplicit(r.bool())
+		return n
 
 	case ir.OCOPY, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCAP, ir.OCLOSE, ir.ODELETE, ir.OLEN, ir.OMAKE, ir.ONEW, ir.OPANIC, ir.ORECOVER, ir.OPRINT, ir.OPRINTN, ir.OUNSAFEADD, ir.OUNSAFESLICE:
 		pos := r.pos()
diff --git a/src/cmd/compile/internal/types/pkg.go b/src/cmd/compile/internal/types/pkg.go
index 4bf39a5..9a21494 100644
--- a/src/cmd/compile/internal/types/pkg.go
+++ b/src/cmd/compile/internal/types/pkg.go
@@ -16,9 +16,6 @@
 // pkgMap maps a package path to a package.
 var pkgMap = make(map[string]*Pkg)
 
-// MaxPkgHeight is a height greater than any likely package height.
-const MaxPkgHeight = 1e9
-
 type Pkg struct {
 	Path    string // string literal used in import statement, e.g. "runtime/internal/sys"
 	Name    string // package name, e.g. "sys"
@@ -26,12 +23,6 @@
 	Syms    map[string]*Sym
 	Pathsym *obj.LSym
 
-	// Height is the package's height in the import graph. Leaf
-	// packages (i.e., packages with no imports) have height 0,
-	// and all other packages have height 1 plus the maximum
-	// height of their imported packages.
-	Height int
-
 	Direct bool // imported directly
 }
 
diff --git a/src/cmd/compile/internal/types/sym.go b/src/cmd/compile/internal/types/sym.go
index 927ebc45..9d8707b 100644
--- a/src/cmd/compile/internal/types/sym.go
+++ b/src/cmd/compile/internal/types/sym.go
@@ -97,14 +97,7 @@
 // Less reports whether symbol a is ordered before symbol b.
 //
 // Symbols are ordered exported before non-exported, then by name, and
-// finally (for non-exported symbols) by package height and path.
-//
-// Ordering by package height is necessary to establish a consistent
-// ordering for non-exported names with the same spelling but from
-// different packages. We don't necessarily know the path for the
-// package being compiled, but by definition it will have a height
-// greater than any other packages seen within the compilation unit.
-// For more background, see issue #24693.
+// finally (for non-exported symbols) by package path.
 func (a *Sym) Less(b *Sym) bool {
 	if a == b {
 		return false
@@ -131,9 +124,6 @@
 		return a.Name < b.Name
 	}
 	if !ea {
-		if a.Pkg.Height != b.Pkg.Height {
-			return a.Pkg.Height < b.Pkg.Height
-		}
 		return a.Pkg.Path < b.Pkg.Path
 	}
 	return false
diff --git a/src/internal/pkgbits/sync.go b/src/internal/pkgbits/sync.go
index 4b9ea48..77178af 100644
--- a/src/internal/pkgbits/sync.go
+++ b/src/internal/pkgbits/sync.go
@@ -90,6 +90,7 @@
 	SyncExprs
 	SyncExpr
 	SyncExprType
+	SyncAssign
 	SyncOp
 	SyncFuncLit
 	SyncCompLit
diff --git a/src/internal/pkgbits/syncmarker_string.go b/src/internal/pkgbits/syncmarker_string.go
index 39db9ed..4a5b0ca 100644
--- a/src/internal/pkgbits/syncmarker_string.go
+++ b/src/internal/pkgbits/syncmarker_string.go
@@ -45,39 +45,40 @@
 	_ = x[SyncExprs-35]
 	_ = x[SyncExpr-36]
 	_ = x[SyncExprType-37]
-	_ = x[SyncOp-38]
-	_ = x[SyncFuncLit-39]
-	_ = x[SyncCompLit-40]
-	_ = x[SyncDecl-41]
-	_ = x[SyncFuncBody-42]
-	_ = x[SyncOpenScope-43]
-	_ = x[SyncCloseScope-44]
-	_ = x[SyncCloseAnotherScope-45]
-	_ = x[SyncDeclNames-46]
-	_ = x[SyncDeclName-47]
-	_ = x[SyncStmts-48]
-	_ = x[SyncBlockStmt-49]
-	_ = x[SyncIfStmt-50]
-	_ = x[SyncForStmt-51]
-	_ = x[SyncSwitchStmt-52]
-	_ = x[SyncRangeStmt-53]
-	_ = x[SyncCaseClause-54]
-	_ = x[SyncCommClause-55]
-	_ = x[SyncSelectStmt-56]
-	_ = x[SyncDecls-57]
-	_ = x[SyncLabeledStmt-58]
-	_ = x[SyncUseObjLocal-59]
-	_ = x[SyncAddLocal-60]
-	_ = x[SyncLinkname-61]
-	_ = x[SyncStmt1-62]
-	_ = x[SyncStmtsEnd-63]
-	_ = x[SyncLabel-64]
-	_ = x[SyncOptLabel-65]
+	_ = x[SyncAssign-38]
+	_ = x[SyncOp-39]
+	_ = x[SyncFuncLit-40]
+	_ = x[SyncCompLit-41]
+	_ = x[SyncDecl-42]
+	_ = x[SyncFuncBody-43]
+	_ = x[SyncOpenScope-44]
+	_ = x[SyncCloseScope-45]
+	_ = x[SyncCloseAnotherScope-46]
+	_ = x[SyncDeclNames-47]
+	_ = x[SyncDeclName-48]
+	_ = x[SyncStmts-49]
+	_ = x[SyncBlockStmt-50]
+	_ = x[SyncIfStmt-51]
+	_ = x[SyncForStmt-52]
+	_ = x[SyncSwitchStmt-53]
+	_ = x[SyncRangeStmt-54]
+	_ = x[SyncCaseClause-55]
+	_ = x[SyncCommClause-56]
+	_ = x[SyncSelectStmt-57]
+	_ = x[SyncDecls-58]
+	_ = x[SyncLabeledStmt-59]
+	_ = x[SyncUseObjLocal-60]
+	_ = x[SyncAddLocal-61]
+	_ = x[SyncLinkname-62]
+	_ = x[SyncStmt1-63]
+	_ = x[SyncStmtsEnd-64]
+	_ = x[SyncLabel-65]
+	_ = x[SyncOptLabel-66]
 }
 
-const _SyncMarker_name = "EOFBoolInt64Uint64StringValueValRelocsRelocUseRelocPublicPosPosBaseObjectObject1PkgPkgDefMethodTypeTypeIdxTypeParamNamesSignatureParamsParamCodeObjSymLocalIdentSelectorPrivateFuncExtVarExtTypeExtPragmaExprListExprsExprAssertTypeOpFuncLitCompLitDeclFuncBodyOpenScopeCloseScopeCloseAnotherScopeDeclNamesDeclNameStmtsBlockStmtIfStmtForStmtSwitchStmtRangeStmtCaseClauseCommClauseSelectStmtDeclsLabeledStmtUseObjLocalAddLocalLinknameStmt1StmtsEndLabelOptLabel"
+const _SyncMarker_name = "EOFBoolInt64Uint64StringValueValRelocsRelocUseRelocPublicPosPosBaseObjectObject1PkgPkgDefMethodTypeTypeIdxTypeParamNamesSignatureParamsParamCodeObjSymLocalIdentSelectorPrivateFuncExtVarExtTypeExtPragmaExprListExprsExprExprTypeAssignOpFuncLitCompLitDeclFuncBodyOpenScopeCloseScopeCloseAnotherScopeDeclNamesDeclNameStmtsBlockStmtIfStmtForStmtSwitchStmtRangeStmtCaseClauseCommClauseSelectStmtDeclsLabeledStmtUseObjLocalAddLocalLinknameStmt1StmtsEndLabelOptLabel"
 
-var _SyncMarker_index = [...]uint16{0, 3, 7, 12, 18, 24, 29, 32, 38, 43, 51, 57, 60, 67, 73, 80, 83, 89, 95, 99, 106, 120, 129, 135, 140, 147, 150, 160, 168, 175, 182, 188, 195, 201, 209, 214, 218, 228, 230, 237, 244, 248, 256, 265, 275, 292, 301, 309, 314, 323, 329, 336, 346, 355, 365, 375, 385, 390, 401, 412, 420, 428, 433, 441, 446, 454}
+var _SyncMarker_index = [...]uint16{0, 3, 7, 12, 18, 24, 29, 32, 38, 43, 51, 57, 60, 67, 73, 80, 83, 89, 95, 99, 106, 120, 129, 135, 140, 147, 150, 160, 168, 175, 182, 188, 195, 201, 209, 214, 218, 226, 232, 234, 241, 248, 252, 260, 269, 279, 296, 305, 313, 318, 327, 333, 340, 350, 359, 369, 379, 389, 394, 405, 416, 424, 432, 437, 445, 450, 458}
 
 func (i SyncMarker) String() string {
 	i -= 1
diff --git a/test/fixedbugs/issue42284.dir/b.go b/test/fixedbugs/issue42284.dir/b.go
index 652aa32..8cd93b8 100644
--- a/test/fixedbugs/issue42284.dir/b.go
+++ b/test/fixedbugs/issue42284.dir/b.go
@@ -7,7 +7,7 @@
 import "./a"
 
 func g() {
-	h := a.E() // ERROR "inlining call to a.E" "a.I\(a.T\(0\)\) does not escape"
+	h := a.E() // ERROR "inlining call to a.E" "T\(0\) does not escape"
 	h.M()      // ERROR "devirtualizing h.M to a.T"
 
 	// BAD: T(0) could be stack allocated.
diff --git a/test/fixedbugs/issue52128.dir/a.go b/test/fixedbugs/issue52128.dir/a.go
new file mode 100644
index 0000000..0abf831
--- /dev/null
+++ b/test/fixedbugs/issue52128.dir/a.go
@@ -0,0 +1,21 @@
+// Copyright 2022 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
+
+type I interface{}
+
+type F func()
+
+type s struct {
+	f F
+}
+
+func NewWithF(f F) *s {
+	return &s{f: f}
+}
+
+func NewWithFuncI(func() I) *s {
+	return &s{}
+}
diff --git a/test/fixedbugs/issue52128.dir/b.go b/test/fixedbugs/issue52128.dir/b.go
new file mode 100644
index 0000000..86f6ed7
--- /dev/null
+++ b/test/fixedbugs/issue52128.dir/b.go
@@ -0,0 +1,17 @@
+// Copyright 2022 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"
+)
+
+type S struct{}
+
+func (s *S) M1() a.I {
+	return a.NewWithF(s.M2)
+}
+
+func (s *S) M2() {}
diff --git a/test/fixedbugs/issue52128.dir/p.go b/test/fixedbugs/issue52128.dir/p.go
new file mode 100644
index 0000000..d3f3dbb
--- /dev/null
+++ b/test/fixedbugs/issue52128.dir/p.go
@@ -0,0 +1,14 @@
+// Copyright 2022 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
+
+import (
+	"./a"
+	"./b"
+)
+
+func f() {
+	a.NewWithFuncI((&b.S{}).M1)
+}
diff --git a/test/fixedbugs/issue52128.go b/test/fixedbugs/issue52128.go
new file mode 100644
index 0000000..8bb5c3e
--- /dev/null
+++ b/test/fixedbugs/issue52128.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2022 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/issue7921.go b/test/fixedbugs/issue7921.go
index 65be4b5..f9efb7f 100644
--- a/test/fixedbugs/issue7921.go
+++ b/test/fixedbugs/issue7921.go
@@ -41,7 +41,7 @@
 
 func bufferNoEscape4() []byte {
 	var b bytes.Buffer
-	b.Grow(64) // ERROR "bufferNoEscape4 ignoring self-assignment in bytes.b.buf = bytes.b.buf\[:bytes.m\]$" "inlining call to bytes.\(\*Buffer\).Grow$" "string\(.*\) escapes to heap"
+	b.Grow(64) // ERROR "bufferNoEscape4 ignoring self-assignment in bytes.b.buf = bytes.b.buf\[:bytes.m\]$" "inlining call to bytes.\(\*Buffer\).Grow$" `".+" escapes to heap`
 	useBuffer(&b)
 	return b.Bytes() // ERROR "inlining call to bytes.\(\*Buffer\).Bytes$"
 }
diff --git a/test/inline.go b/test/inline.go
index 400898b..04ba168 100644
--- a/test/inline.go
+++ b/test/inline.go
@@ -107,18 +107,6 @@
 	return foo()                       // ERROR "inlining call to q.func1"
 }
 
-func r(z int) int {
-	foo := func(x int) int { // ERROR "can inline r.func1" "func literal does not escape"
-		return x + z
-	}
-	bar := func(x int) int { // ERROR "func literal does not escape" "can inline r.func2"
-		return x + func(y int) int { // ERROR "can inline r.func2.1" "can inline r.func3"
-			return 2*y + x*z
-		}(x) // ERROR "inlining call to r.func2.1"
-	}
-	return foo(42) + bar(42) // ERROR "inlining call to r.func1" "inlining call to r.func2" "inlining call to r.func3"
-}
-
 func s0(x int) int { // ERROR "can inline s0"
 	foo := func() { // ERROR "can inline s0.func1" "func literal does not escape"
 		x = x + 1
diff --git a/test/inline_nounified.go b/test/inline_nounified.go
new file mode 100644
index 0000000..7a9fc10
--- /dev/null
+++ b/test/inline_nounified.go
@@ -0,0 +1,21 @@
+// errorcheckwithauto -0 -m -d=inlfuncswithclosures=1
+//go:build !goexperiment.unified
+// +build !goexperiment.unified
+
+// Copyright 2022 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 foo
+
+func r(z int) int {
+	foo := func(x int) int { // ERROR "can inline r.func1" "func literal does not escape"
+		return x + z
+	}
+	bar := func(x int) int { // ERROR "func literal does not escape" "can inline r.func2"
+		return x + func(y int) int { // ERROR "can inline r.func2.1" "can inline r.func3"
+			return 2*y + x*z
+		}(x) // ERROR "inlining call to r.func2.1"
+	}
+	return foo(42) + bar(42) // ERROR "inlining call to r.func1" "inlining call to r.func2" "inlining call to r.func3"
+}
diff --git a/test/inline_unified.go b/test/inline_unified.go
new file mode 100644
index 0000000..ff70e44
--- /dev/null
+++ b/test/inline_unified.go
@@ -0,0 +1,21 @@
+// errorcheckwithauto -0 -m -d=inlfuncswithclosures=1
+//go:build goexperiment.unified
+// +build goexperiment.unified
+
+// Copyright 2022 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 foo
+
+func r(z int) int {
+	foo := func(x int) int { // ERROR "can inline r.func1" "func literal does not escape"
+		return x + z
+	}
+	bar := func(x int) int { // ERROR "func literal does not escape" "can inline r.func2"
+		return x + func(y int) int { // ERROR "can inline r.func2.1"
+			return 2*y + x*z
+		}(x) // ERROR "inlining call to r.func2.1"
+	}
+	return foo(42) + bar(42) // ERROR "inlining call to r.func1" "inlining call to r.func2" "can inline r.func3" "inlining call to r.func3"
+}
diff --git a/test/run.go b/test/run.go
index cb1622c..b0156fb 100644
--- a/test/run.go
+++ b/test/run.go
@@ -1964,8 +1964,10 @@
 )
 
 var go118Failures = setOf(
-	"typeparam/nested.go",     // 1.18 compiler doesn't support function-local types with generics
-	"typeparam/issue51521.go", // 1.18 compiler produces bad panic message and link error
+	"typeparam/nested.go",      // 1.18 compiler doesn't support function-local types with generics
+	"typeparam/issue51521.go",  // 1.18 compiler produces bad panic message and link error
+	"typeparam/mdempsky/16.go", // 1.18 compiler uses interface shape type in failed type assertions
+	"typeparam/mdempsky/17.go", // 1.18 compiler mishandles implicit conversions from range loops
 )
 
 // In all of these cases, the 1.17 compiler reports reasonable errors, but either the
@@ -1993,18 +1995,10 @@
 )
 
 var unifiedFailures = setOf(
-	"closure3.go",  // unified IR numbers closures differently than -d=inlfuncswithclosures
-	"escape4.go",   // unified IR can inline f5 and f6; test doesn't expect this
-	"inline.go",    // unified IR reports function literal diagnostics on different lines than -d=inlfuncswithclosures
-	"linkname3.go", // unified IR is missing some linkname errors
+	"closure3.go", // unified IR numbers closures differently than -d=inlfuncswithclosures
+	"escape4.go",  // unified IR can inline f5 and f6; test doesn't expect this
 
-	"fixedbugs/issue42284.go",  // prints "T(0) does not escape", but test expects "a.I(a.T(0)) does not escape"
-	"fixedbugs/issue7921.go",   // prints "… escapes to heap", but test expects "string(…) escapes to heap"
-	"typeparam/issue47631.go",  // unified IR can handle local type declarations
-	"fixedbugs/issue42058a.go", // unified IR doesn't report channel element too large
-	"fixedbugs/issue42058b.go", // unified IR doesn't report channel element too large
-	"fixedbugs/issue49767.go",  // unified IR doesn't report channel element too large
-	"fixedbugs/issue49814.go",  // unified IR doesn't report array type too large
+	"typeparam/issue47631.go", // unified IR can handle local type declarations
 )
 
 func setOf(keys ...string) map[string]bool {
diff --git a/test/typeparam/mdempsky/16.go b/test/typeparam/mdempsky/16.go
new file mode 100644
index 0000000..f4f79b9
--- /dev/null
+++ b/test/typeparam/mdempsky/16.go
@@ -0,0 +1,34 @@
+// run
+
+// Copyright 2022 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 that type assertion panics mention the real interface type,
+// not their shape type.
+
+package main
+
+import (
+	"fmt"
+	"runtime"
+	"strings"
+)
+
+func main() {
+	// The exact error message isn't important, but it should mention
+	// `main.T`, not `go.shape.int_0`.
+	if have := F[T](); !strings.Contains(have, "interface { T() main.T }") {
+		fmt.Printf("FAIL: unexpected panic message: %q\n", have)
+	}
+}
+
+type T int
+
+func F[T any]() (res string) {
+	defer func() {
+		res = recover().(runtime.Error).Error()
+	}()
+	_ = interface{ T() T }(nil).(T)
+	return
+}
diff --git a/test/typeparam/mdempsky/17.go b/test/typeparam/mdempsky/17.go
new file mode 100644
index 0000000..12385c3
--- /dev/null
+++ b/test/typeparam/mdempsky/17.go
@@ -0,0 +1,110 @@
+// run
+
+// Copyright 2022 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 that implicit conversions of derived types to interface type
+// in range loops work correctly.
+
+package main
+
+import (
+	"fmt"
+	"reflect"
+)
+
+func main() {
+	test{"int", "V"}.match(RangeArrayAny[V]())
+	test{"int", "V"}.match(RangeArrayIface[V]())
+	test{"V"}.match(RangeChanAny[V]())
+	test{"V"}.match(RangeChanIface[V]())
+	test{"K", "V"}.match(RangeMapAny[K, V]())
+	test{"K", "V"}.match(RangeMapIface[K, V]())
+	test{"int", "V"}.match(RangeSliceAny[V]())
+	test{"int", "V"}.match(RangeSliceIface[V]())
+}
+
+type test []string
+
+func (t test) match(args ...any) {
+	if len(t) != len(args) {
+		fmt.Printf("FAIL: want %v values, have %v\n", len(t), len(args))
+		return
+	}
+	for i, want := range t {
+		if have := reflect.TypeOf(args[i]).Name(); want != have {
+			fmt.Printf("FAIL: %v: want type %v, have %v\n", i, want, have)
+		}
+	}
+}
+
+type iface interface{ M() int }
+
+type K int
+type V int
+
+func (K) M() int { return 0 }
+func (V) M() int { return 0 }
+
+func RangeArrayAny[V any]() (k, v any) {
+	for k, v = range [...]V{zero[V]()} {
+	}
+	return
+}
+
+func RangeArrayIface[V iface]() (k any, v iface) {
+	for k, v = range [...]V{zero[V]()} {
+	}
+	return
+}
+
+func RangeChanAny[V any]() (v any) {
+	for v = range chanOf(zero[V]()) {
+	}
+	return
+}
+
+func RangeChanIface[V iface]() (v iface) {
+	for v = range chanOf(zero[V]()) {
+	}
+	return
+}
+
+func RangeMapAny[K comparable, V any]() (k, v any) {
+	for k, v = range map[K]V{zero[K](): zero[V]()} {
+	}
+	return
+}
+
+func RangeMapIface[K interface {
+	iface
+	comparable
+}, V iface]() (k, v iface) {
+	for k, v = range map[K]V{zero[K](): zero[V]()} {
+	}
+	return
+}
+
+func RangeSliceAny[V any]() (k, v any) {
+	for k, v = range []V{zero[V]()} {
+	}
+	return
+}
+
+func RangeSliceIface[V iface]() (k any, v iface) {
+	for k, v = range []V{zero[V]()} {
+	}
+	return
+}
+
+func chanOf[T any](elems ...T) chan T {
+	c := make(chan T, len(elems))
+	for _, elem := range elems {
+		c <- elem
+	}
+	close(c)
+	return c
+}
+
+func zero[T any]() (_ T) { return }