Repository: goadesign/goa (go)

Issue:
Goa generating invalid code when OneOf types is a user defined type
When a `ResultType` had a field that is union type and one of the fields of the union type is a user type the goa is generating code that doesn't compile.

Design
```
package design

import (
	. "goa.design/goa/v3/dsl"
)

var _ = Service("Cars Service", func() {
	Description(`Test Cars Service`)

	Method("get_car", func() {
		Description("Fetches list of cars.")
		Payload(func() {
			Field(1, "ID", Int64, "ID of the car")
			Required("ID")
		})
		Result(Car)

		Error("internal")
		GRPC(func() {
			Response(CodeOK)
			Response("internal", CodeInternal)
		})
	})
})

var Car = ResultType("Car", "Car", func() {
	Description("Test Car")

	Field(1, "ID", Int64, "ID of the car")
	Field(2, "Name", String, "Name of the car")
	Field(3, "Type", CarType, "Model of the car")
	Field(4, "Year", Int, "Year of the car")

	Required("ID", "Name")
})

var CarType = Type("CarType", func() {
	Description("Car Type")

	OneOf("Type", func() {
		Field(1, "Sedan", Sedan, "Type of the car")
		Field(2, "SUV", SUV, "Type of the car")
	})

	Required("Type")
})

var Sedan = Type("Sedan", func() {
	Description("Sedan Type")

	Field(1, "DriveType", String, "Model of the car")
	Field(2, "Seats", Count, "Number of seats")

	Required("DriveType")
})

var SUV = Type("SUV", func() {
	Description("SUV Type")

	Field(1, "DriveType", String, "Model of the car")
	Field(2, "Seats", Count, "Number of seats")
	Field(3, "TowingCapacity", TowingCapacity, "Towing capacity of the car")

	Required("DriveType")
})

var Count = Type("Count", Int, func() {
	Description("Seat Count")
	Maximum(7)
	Minimum(2)
})

var TowingCapacity = Type("TowingCapacity", Int, func() {
	Description("Towing Capacity")
	Maximum(10000)
	Minimum(1000)
})
```
The generated code to transform the view to actual type and actual type to view is invalid
```
// transformCarsserviceviewsCarTypeViewToCarType builds a value of type
// *CarType from a value of type *carsserviceviews.CarTypeView.
func transformCarsserviceviewsCarTypeViewToCarType(v *carsserviceviews.CarTypeView) *CarType {
	if v == nil {
		return nil
	}
	res := &CarType{}
	if v.Type != nil {
		switch actual := v.Type.(type) {
		case *carsserviceviews.SedanView:
			res.Type = &Sedan{
				DriveType: *actual.DriveType,
			}
			if actual.Seats != nil {
				seats := Count(*actual.Seats)
				res.Type.Seats = &seats
			}

		case *carsserviceviews.SUVView:
			res.Type = &SUV{
				DriveType: *actual.DriveType,
			}
			if actual.Seats != nil {
				seats := Count(*actual.Seats)
				res.Type.Seats = &seats
			}
			if actual.TowingCapacity != nil {
				towingCapacity := TowingCapacity(*actual.TowingCapacity)
				res.Type.TowingCapacity = &towingCapacity
			}

		}
	}

	return res
}
```


Pull request:
Correctly handle union to union transforms
These happen when using views and `OneOf`.
Fix #3489 

Patch:
diff --git a/codegen/go_transform.go b/codegen/go_transform.go
index 805ea43e..821d477e 100644
--- a/codegen/go_transform.go
+++ b/codegen/go_transform.go
@@ -698,7 +698,8 @@ for key, val := range {{ .SourceVar }} {
 {{ end }}switch actual := {{ .SourceVar }}.(type) {
 	{{- range $i, $ref := .SourceTypeRefs }}
 	case {{ $ref }}:
-		{{- transformAttribute (index $.SourceTypes $i).Attribute (index $.TargetTypes $i).Attribute "actual" $.TargetVar false $.TransformAttrs -}}
+		{{- transformAttribute (index $.SourceTypes $i).Attribute (index $.TargetTypes $i).Attribute "actual" "obj" true $.TransformAttrs -}}
+		{{ $.TargetVar }} = obj
 	{{- end }}
 }
 `


Test patch:
diff --git a/codegen/go_transform_union_test.go b/codegen/go_transform_union_test.go
index c864b3d6..4d02aec1 100644
--- a/codegen/go_transform_union_test.go
+++ b/codegen/go_transform_union_test.go
@@ -91,8 +91,8 @@ const unionToUnionCode = `func transform() {
 	var target *UnionString2
 	switch actual := source.(type) {
 	case UnionStringString:
-		target = UnionString2String(actual)
-
+		obj := UnionString2String(actual)
+		target = obj
 	}
 }
 `
@@ -101,11 +101,11 @@ const unionMultiToUnionMultiCode = `func transform() {
 	var target *UnionStringInt2
 	switch actual := source.(type) {
 	case UnionStringIntString:
-		target = UnionStringInt2String(actual)
-
+		obj := UnionStringInt2String(actual)
+		target = obj
 	case UnionStringIntInt:
-		target = UnionStringInt2Int(actual)
-
+		obj := UnionStringInt2Int(actual)
+		target = obj
 	}
 }
 `
diff --git a/codegen/service/testdata/service_code.go b/codegen/service/testdata/service_code.go
index 353cc117..26b9a9bd 100644
--- a/codegen/service/testdata/service_code.go
+++ b/codegen/service/testdata/service_code.go
@@ -1516,16 +1516,16 @@ func newResultOneof(vres *resultwithoneoftypeviews.ResultOneofView) *ResultOneof
 	if vres.Result != nil {
 		switch actual := vres.Result.(type) {
 		case *resultwithoneoftypeviews.TView:
-			res.Result = &T{
+			obj := &T{
 				Message: actual.Message,
 			}
-
+			res.Result = obj
 		case *resultwithoneoftypeviews.UView:
-			res.Result = &U{}
+			obj := &U{}
 			if actual.Item != nil {
-				res.Result.(*U).Item = transformResultwithoneoftypeviewsItemViewToItem(actual.Item)
+				obj.(*U).Item = transformResultwithoneoftypeviewsItemViewToItem(actual.Item)
 			}
-
+			res.Result = obj
 		}
 	}
 	return res
@@ -1538,16 +1538,16 @@ func newResultOneofView(res *ResultOneof) *resultwithoneoftypeviews.ResultOneofV
 	if res.Result != nil {
 		switch actual := res.Result.(type) {
 		case *T:
-			vres.Result = &resultwithoneoftypeviews.TView{
+			obj := &resultwithoneoftypeviews.TView{
 				Message: actual.Message,
 			}
-
+			vres.Result = obj
 		case *U:
-			vres.Result = &resultwithoneoftypeviews.UView{}
+			obj := &resultwithoneoftypeviews.UView{}
 			if actual.Item != nil {
-				vres.Result.(*resultwithoneoftypeviews.UView).Item = transformItemToResultwithoneoftypeviewsItemView(actual.Item)
+				obj.(*resultwithoneoftypeviews.UView).Item = transformItemToResultwithoneoftypeviewsItemView(actual.Item)
 			}
-
+			vres.Result = obj
 		}
 	}
 	return vres