func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) { if len(t.Members) == 0 { // at least do something with in/out to avoid "declared and not used" errors sw.Do("_ = in\n_ = out\n", nil) } for _, m := range t.Members { t := m.Type if t.Kind == types.Alias { copied := *t.Underlying copied.Name = t.Name t = &copied } args := map[string]interface{}{ "type": t, "name": m.Name, } switch t.Kind { case types.Builtin: sw.Do("out.$.name$ = in.$.name$\n", args) case types.Map, types.Slice, types.Pointer: sw.Do("if in.$.name$ != nil {\n", args) sw.Do("in, out := &in.$.name$, &out.$.name$\n", args) g.generateFor(t, sw) sw.Do("} else {\n", nil) sw.Do("out.$.name$ = nil\n", args) sw.Do("}\n", nil) case types.Struct: if hasDeepCopyMethod(t) { sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args) } else if t.IsAssignable() { sw.Do("out.$.name$ = in.$.name$\n", args) } else if g.copyableAndInBounds(t) { funcName := g.funcNameTmpl(t) sw.Do(fmt.Sprintf("if err := %s(&in.$.name$, &out.$.name$, c); err != nil {\n", funcName), args) sw.Do("return err\n", nil) sw.Do("}\n", nil) } else { sw.Do("if newVal, err := c.DeepCopy(&in.$.name$); err != nil {\n", args) sw.Do("return err\n", nil) sw.Do("} else {\n", nil) sw.Do("out.$.name$ = *newVal.(*$.type|raw$)\n", args) sw.Do("}\n", nil) } default: sw.Do("if in.$.name$ == nil {\n", args) sw.Do("out.$.name$ = nil\n", args) sw.Do("} else if newVal, err := c.DeepCopy(&in.$.name$); err != nil {\n", args) sw.Do("return err\n", nil) sw.Do("} else {\n", nil) sw.Do("out.$.name$ = *newVal.(*$.type|raw$)\n", args) sw.Do("}\n", nil) } } }
func isDirectlyAssignable(inType, outType *types.Type) bool { // TODO: This should maybe check for actual assignability between the two // types, rather than superficial traits that happen to indicate it is // assignable in the ways we currently use this code. return inType.IsAssignable() && (inType.IsPrimitive() || isSamePackage(inType, outType)) }