// markType recursively visits types reachable from t to identify
 // functions whose inline bodies may be needed.
 func (p *exporter) markType(t *types.Type) {
-       if p.marked[t] {
+       if t.IsInstantiatedGeneric() {
+               // Re-instantiated types don't add anything new, so don't follow them.
                return
        }
-       p.marked[t] = true
-       if t.HasTParam() {
-               // Don't deal with any generic types or their methods, since we
-               // will only be inlining actual instantiations, not generic methods.
+       if p.marked[t] {
                return
        }
+       p.marked[t] = true
 
        // If this is a named type, mark all of its associated
        // methods. Skip interface types because t.Methods contains
                                p.markType(f.Type)
                        }
                }
+
+       case types.TTYPEPARAM:
+               // No other type that needs to be followed.
        }
 }
 
        }
 
        g.funcBody(fn, decl.Recv, decl.Type, decl.Body)
+       if fn.Type().HasTParam() && fn.Body != nil {
+               // Set pointers to the dcls/body of a generic function/method in
+               // the Inl struct, so it is marked for export, is available for
+               // stenciling, and works with Inline_Flood().
+               fn.Inl = &ir.Inline{
+                       Cost: 1,
+                       Dcl:  fn.Dcl,
+                       Body: fn.Body,
+               }
+       }
 
        out.Append(fn)
 }
 
        "go/constant"
 )
 
-// For catching problems as we add more features
-// TODO(danscales): remove assertions or replace with base.FatalfAt()
 func assert(p bool) {
        if !p {
                panic("assertion failed")
 
                // in the local package, even if they may be marked as part of
                // another package (the package of their base generic type).
                if tbase.Sym() != nil && tbase.Sym().Pkg != types.LocalPkg &&
-                       !tbase.IsInstantiated() {
+                       !tbase.IsFullyInstantiated() {
                        if i := typecheck.BaseTypeIndex(t); i >= 0 {
                                lsym.Pkg = tbase.Sym().Pkg.Prefix
                                lsym.SymIdx = int32(i)
        // instantiated methods.
        if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type &&
                rcvr.Elem().Sym() != nil && rcvr.Elem().Sym().Pkg != types.LocalPkg &&
-               !rcvr.Elem().IsInstantiated() {
+               !rcvr.Elem().IsFullyInstantiated() {
                return lsym
        }
 
 
 
                                f := t.Field(i)
                                s := f.Sym
-                               if s != nil && !types.IsExported(s.Name) && s.Pkg != types.LocalPkg {
-                                       base.Errorf("implicit assignment of unexported field '%s' in %v literal", s.Name, t)
+
+                               // Do the test for assigning to unexported fields.
+                               // But if this is an instantiated function, then
+                               // the function has already been typechecked. In
+                               // that case, don't do the test, since it can fail
+                               // for the closure structs created in
+                               // walkClosure(), because the instantiated
+                               // function is compiled as if in the source
+                               // package of the generic function.
+                               if !(ir.CurFunc != nil && strings.Index(ir.CurFunc.Nname.Sym().Name, "[") >= 0) {
+                                       if s != nil && !types.IsExported(s.Name) && s.Pkg != types.LocalPkg {
+                                               base.Errorf("implicit assignment of unexported field '%s' in %v literal", s.Name, t)
+                                       }
                                }
                                // No pushtype allowed here. Must name fields for that.
                                n1 = AssignConv(n1, f.Type, "field value")
 
        // The information appears in the binary in the form of type descriptors;
        // the struct is unnamed so that closures in multiple packages with the
        // same struct type can share the descriptor.
+
+       // Make sure the .F field is in the same package as the rest of the
+       // fields. This deals with closures in instantiated functions, which are
+       // compiled as if from the source package of the generic function.
+       var pkg *types.Pkg
+       if len(clo.Func.ClosureVars) == 0 {
+               pkg = types.LocalPkg
+       } else {
+               for _, v := range clo.Func.ClosureVars {
+                       if pkg == nil {
+                               pkg = v.Sym().Pkg
+                       } else if pkg != v.Sym().Pkg {
+                               base.Fatalf("Closure variables from multiple packages")
+                       }
+               }
+       }
+
        fields := []*types.Field{
-               types.NewField(base.Pos, Lookup(".F"), types.Types[types.TUINTPTR]),
+               types.NewField(base.Pos, pkg.Lookup(".F"), types.Types[types.TUINTPTR]),
        }
        for _, v := range clo.Func.ClosureVars {
                typ := v.Type()
 
                }
        }
 
-       // Inline body.
-       if n.Type().HasTParam() {
-               if n.Func.Inl != nil {
-                       // n.Func.Inl may already be set on a generic function if
-                       // we imported it from another package, but shouldn't be
-                       // set for a generic function in the local package.
-                       if n.Sym().Pkg == types.LocalPkg {
-                               base.FatalfAt(n.Pos(), "generic function is marked inlineable")
-                       }
-               } else {
-                       // Populate n.Func.Inl, so body of exported generic function will
-                       // be written out.
-                       n.Func.Inl = &ir.Inline{
-                               Cost: 1,
-                               Dcl:  n.Func.Dcl,
-                               Body: n.Func.Body,
-                       }
-               }
+       // Write out inline body or body of a generic function/method.
+       if n.Type().HasTParam() && n.Func.Body != nil && n.Func.Inl == nil {
+               base.FatalfAt(n.Pos(), "generic function is not marked inlineable")
        }
        if n.Func.Inl != nil {
                w.uint64(1 + uint64(n.Func.Inl.Cost))
 
        "cmd/compile/internal/base"
        "cmd/internal/src"
        "fmt"
+       "strings"
        "sync"
 )
 
        }
 }
 
-// IsInstantiated reports whether t is a fully instantiated generic type; i.e. an
+// IsBaseGeneric returns true if t is a generic type (not reinstantiated with
+// another type params or fully instantiated.
+func (t *Type) IsBaseGeneric() bool {
+       return len(t.RParams()) > 0 && strings.Index(t.Sym().Name, "[") < 0
+}
+
+// IsInstantiatedGeneric returns t if t ia generic type that has been
+// reinstantiated with new typeparams (i.e. is not fully instantiated).
+func (t *Type) IsInstantiatedGeneric() bool {
+       return len(t.RParams()) > 0 && strings.Index(t.Sym().Name, "[") >= 0 &&
+               t.HasTParam()
+}
+
+// IsFullyInstantiated reports whether t is a fully instantiated generic type; i.e. an
 // instantiated generic type where all type arguments are non-generic or fully
 // instantiated generic types.
-func (t *Type) IsInstantiated() bool {
+func (t *Type) IsFullyInstantiated() bool {
        return len(t.RParams()) > 0 && !t.HasTParam()
 }
 
 
 }
 
 // iterate returns an iterator that traverses the map.
-// func (m *Map[K, V]) Iterate() *Iterator[K, V] {
-//     sender, receiver := Ranger[keyValue[K, V]]()
-//     var f func(*node[K, V]) bool
-//     f = func(n *node[K, V]) bool {
-//             if n == nil {
-//                     return true
-//             }
-//             // Stop the traversal if Send fails, which means that
-//             // nothing is listening to the receiver.
-//             return f(n.left) &&
-//                     sender.Send(context.Background(), keyValue[K, V]{n.key, n.val}) &&
-//                     f(n.right)
-//     }
-//     go func() {
-//             f(m.root)
-//             sender.Close()
-//     }()
-//     return &Iterator[K, V]{receiver}
-// }
+func (m *Map[K, V]) Iterate() *Iterator[K, V] {
+       sender, receiver := Ranger[keyValue[K, V]]()
+       var f func(*node[K, V]) bool
+       f = func(n *node[K, V]) bool {
+               if n == nil {
+                       return true
+               }
+               // Stop the traversal if Send fails, which means that
+               // nothing is listening to the receiver.
+               return f(n.left) &&
+                       sender.Send(context.Background(), keyValue[K, V]{n.key, n.val}) &&
+                       f(n.right)
+       }
+       go func() {
+               f(m.root)
+               sender.Close()
+       }()
+       return &Iterator[K, V]{receiver}
+}
 
 // Iterator is used to iterate over the map.
 type Iterator[K, V any] struct {
 
                panic(fmt.Sprintf("unexpectedly found %q", []byte("d")))
        }
 
-       // TODO(danscales): Iterate() has some things to be fixed with inlining in
-       // stenciled functions and using closures across packages.
-
-       // gather := func(it *a.Iterator[[]byte, int]) []int {
-       //      var r []int
-       //      for {
-       //              _, v, ok := it.Next()
-       //              if !ok {
-       //                      return r
-       //              }
-       //              r = append(r, v)
-       //      }
-       // }
-       // got := gather(m.Iterate())
-       // want := []int{'a', 'b', 'x'}
-       // if !a.SliceEqual(got, want) {
-       //      panic(fmt.Sprintf("Iterate returned %v, want %v", got, want))
-       // }
+       gather := func(it *a.Iterator[[]byte, int]) []int {
+               var r []int
+               for {
+                       _, v, ok := it.Next()
+                       if !ok {
+                               return r
+                       }
+                       r = append(r, v)
+               }
+       }
+       got := gather(m.Iterate())
+       want := []int{'a', 'b', 'x'}
+       if !a.SliceEqual(got, want) {
+               panic(fmt.Sprintf("Iterate returned %v, want %v", got, want))
+       }
 
 }