cue: allow alias reuse in subscopes

Fixes #232

Change-Id: I5a6853926efbb76a86b438e8f5be62bbdd8cd3f1
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/4420
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/ast.go b/cue/ast.go
index bfbaae6..95cbf7e 100644
--- a/cue/ast.go
+++ b/cue/ast.go
@@ -83,7 +83,8 @@
 	allowAuto   bool // allow builtin packages without import
 
 	// make unique per level to avoid reuse of structs being an issue.
-	astMap map[ast.Node]scope
+	astMap   map[ast.Node]scope
+	aliasMap map[ast.Node]value
 
 	errors errors.Error
 }
@@ -120,6 +121,7 @@
 		resolveRoot: resolveRoot,
 		allowAuto:   allowAuto,
 		astMap:      map[ast.Node]scope{},
+		aliasMap:    map[ast.Node]value{},
 	}
 	return v
 }
@@ -528,9 +530,15 @@
 		// Pkg                    nil            ImportSpec
 
 		if x, ok := n.Node.(*ast.Alias); ok {
+			// TODO(lang): should we exempt definitions? The substitution
+			// principle says we should not.
+			if ret = v.aliasMap[x.Expr]; ret != nil {
+				break
+			}
 			old := v.ctx().inDefinition
 			v.ctx().inDefinition = 0
 			ret = v.walk(x.Expr)
+			v.aliasMap[x.Expr] = ret
 			v.ctx().inDefinition = old
 			break
 		}
diff --git a/cue/resolve_test.go b/cue/resolve_test.go
index def9e29..26bde55 100644
--- a/cue/resolve_test.go
+++ b/cue/resolve_test.go
@@ -2854,6 +2854,31 @@
 		foo: json.Marshal(input)
 		`,
 		out: `<0>{input: string, foo: <1>.Marshal (<2>.input)}`,
+	}, {
+		desc: "alias reuse in nested scope",
+		in: `
+		Foo :: {
+			X = or([ k for k, _ in {} ])
+			connection: [X]: X
+		}
+		A :: {
+			foo: "key"
+			X = foo
+			a: foo: [X]: X
+		}
+		B :: {
+			foo: string
+			X = foo
+			a: foo: [X]: X
+		}
+		b: B & { foo: "key" }
+		`,
+		out: `<0>{` +
+			`Foo :: <1>C{connection: <2>C{[or ([ <3>for k, _ in <4>{} yield <3>.k ])]: <5>(_: string)->or ([ <3>for k, _ in <4>{} yield <3>.k ]), }}, ` +
+			`A :: <6>C{foo: "key", a: <7>C{foo: <8>C{["key"]: <9>(_: string)-><10>.foo, }}}, ` +
+			`B :: <11>C{foo: string, a: <12>C{foo: <13>C{[string]: <14>(_: string)-><15>.foo, }}}, ` +
+			`b: <16>C{foo: "key", a: <17>C{foo: <18>C{["key"]: <19>(_: string)-><20>.foo, }}}` +
+			`}`,
 	}}
 	rewriteHelper(t, testCases, evalFull)
 }