go/pointer: fix constraint gen for *ssa.Next

The existing implementation has an error coordinating the types of the
expressions 'k, v' in a range statement over a map 'k, v := range m'.
In particular, 'k', 'v' may have types other than the key and value
types of m and the difference between these types affects the constraint
generation of *ssa.Next (used to model iterating over maps).  This fix
simply calculates the offset of the destination (the *types.Tuple of
*ssa.Next) independently from the offset of the source (the map 'm' in
the example above).

Fixes golang/go#45735

Change-Id: Ib11846a94c23f8815fa502bdb7f80ef0803bf182
Reviewed-on: https://go-review.googlesource.com/c/tools/+/335889
Reviewed-by: Tim King <taking@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
Trust: Tim King <taking@google.com>
Run-TryBot: Tim King <taking@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
diff --git a/go/pointer/gen.go b/go/pointer/gen.go
index 5d2d621..36e1aef 100644
--- a/go/pointer/gen.go
+++ b/go/pointer/gen.go
@@ -1055,16 +1055,42 @@
 		// Do nothing.  Next{Iter: *ssa.Range} handles this case.
 
 	case *ssa.Next:
-		if !instr.IsString { // map
-			// Assumes that Next is always directly applied to a Range result.
+		if !instr.IsString {
+			// Assumes that Next is always directly applied to a Range result
+			// for a map.
+
+			// Next results in a destination tuple (ok, dk, dv).
+			// Recall a map is modeled as type *M where M = struct{sk K; sv V}.
+			// Next copies from a src map struct{sk K; sv V} to a dst tuple (ok, dk, dv)
+			//
+			// When keys or value is a blank identifier in a range statement, e.g
+			//   for _, v := range m { ... }
+			// or
+			//   for _, _ = range m { ... }
+			// we skip copying from sk or dk as there is no use. dk and dv will have
+			// Invalid types if they are blank identifiers. This means that the
+			//   size( (ok, dk, dv) )  may differ from 1 + size(struct{sk K; sv V}).
+			//
+			// We encode Next using one load of size sz from an offset in src osrc to an
+			// offset in dst odst. There are 4 cases to consider:
+			//           odst       | osrc     | sz
+			//   k, v  | 1          | 0        | size(sk) + size(sv)
+			//   k, _  | 1          | 0        | size(sk)
+			//   _, v  | 1+size(dk) | size(sk) | size(sv)
+			//   _, _  | 1+size(dk) | size(sk) | 0
+
+			// get the source key and value size.  Note the source types
+			// may be different than the 3-tuple types, but if this is the
+			// case then the source is assignable to the destination.
 			theMap := instr.Iter.(*ssa.Range).X
 			tMap := theMap.Type().Underlying().(*types.Map)
 
-			ksize := a.sizeof(tMap.Key())
-			vsize := a.sizeof(tMap.Elem())
+			sksize := a.sizeof(tMap.Key())
+			svsize := a.sizeof(tMap.Elem())
 
-			// The k/v components of the Next tuple may each be invalid.
+			// get the key size of the destination tuple.
 			tTuple := instr.Type().(*types.Tuple)
+			dksize := a.sizeof(tTuple.At(1).Type())
 
 			// Load from the map's (k,v) into the tuple's (ok, k, v).
 			osrc := uint32(0) // offset within map object
@@ -1073,15 +1099,15 @@
 
 			// Is key valid?
 			if tTuple.At(1).Type() != tInvalid {
-				sz += ksize
+				sz += sksize
 			} else {
-				odst += ksize
-				osrc += ksize
+				odst += dksize
+				osrc += sksize
 			}
 
 			// Is value valid?
 			if tTuple.At(2).Type() != tInvalid {
-				sz += vsize
+				sz += svsize
 			}
 
 			a.genLoad(cgn, a.valueNode(instr)+nodeid(odst), theMap, osrc, sz)
diff --git a/go/pointer/testdata/maps.go b/go/pointer/testdata/maps.go
index 6729304..f73a6ea 100644
--- a/go/pointer/testdata/maps.go
+++ b/go/pointer/testdata/maps.go
@@ -58,8 +58,8 @@
 	// is ill-typed.
 
 	// sizeof(K) > 1, abstractly
-	type K struct{ a, b *float64 }
-	k := K{new(float64), nil}
+	type K struct{ a, b, c, d *float64 }
+	k := K{new(float64), nil, nil, nil}
 	m := map[K]*int{k: &g}
 
 	for _, v := range m {
@@ -67,8 +67,42 @@
 	}
 }
 
+var v float64
+
+func maps4() {
+	// Regression test for generating constraints for cases of key and values
+	// being blank identifiers or different types assignable from the
+	// corresponding map types in a range stmt.
+	type K struct{ a *float64 }
+	k := K{&v}
+	m := map[K]*int{k: &g}
+
+	for x, y := range m {
+		print(x.a) // @pointsto main.v
+		print(y)   // @pointsto main.g
+	}
+	var i struct{ a *float64 }
+	for i, _ = range m {
+		print(i.a) // @pointsto main.v
+	}
+	var j interface{}
+	for _, j = range m {
+		// TODO support the statement `print(j.(*int))`
+		print(j) // @pointsto main.g
+	}
+	for _, _ = range m {
+	}
+	// do something after 'for _, _ =' to exercise the
+	// effects of indexing
+	for _, j = range m {
+		// TODO support the statement `print(j.(*int))`
+		print(j) // @pointsto main.g
+	}
+}
+
 func main() {
 	maps1()
 	maps2()
 	maps3()
+	maps4()
 }