internal/core/compile: fix alias resolution bug

Fixes #495

Change-Id: Ia8a4b0972e036cd970f921046d5a436f7a8e413e
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/7267
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/testdata/basicrewrite/aliases/aliases.txtar b/cue/testdata/basicrewrite/aliases/aliases.txtar
new file mode 100644
index 0000000..fb1d760
--- /dev/null
+++ b/cue/testdata/basicrewrite/aliases/aliases.txtar
@@ -0,0 +1,34 @@
+-- in.cue --
+t0: {
+	a=_a: _
+	let _b = a
+	_out: _b
+}
+t1: {
+    _a: b
+    let b = c
+    c=d: 3
+}
+-- out/compile --
+--- in.cue
+{
+  t0: {
+    _a: _
+    _out: 〈0;let _b〉
+  }
+  t1: {
+    _a: 〈0;let b〉
+    d: 3
+  }
+}
+-- out/eval --
+(struct){
+  t0: (struct){
+    _a: (_){ _ }
+    _out: (_){ _ }
+  }
+  t1: (struct){
+    _a: (int){ 3 }
+    d: (int){ 3 }
+  }
+}
diff --git a/internal/core/compile/compile.go b/internal/core/compile/compile.go
index 2e7d406..e261193 100644
--- a/internal/core/compile/compile.go
+++ b/internal/core/compile/compile.go
@@ -166,6 +166,15 @@
 	return nil
 }
 
+func (c *compiler) updateAlias(id *ast.Ident, expr adt.Expr) {
+	k := len(c.stack) - 1
+	m := c.stack[k].aliases
+
+	x := m[id.Name]
+	x.expr = expr
+	m[id.Name] = x
+}
+
 // lookupAlias looks up an alias with the given name at the k'th stack position.
 func (c compiler) lookupAlias(k int, id *ast.Ident) aliasEntry {
 	m := c.stack[k].aliases
@@ -441,6 +450,9 @@
 
 func (c *compiler) addDecls(st *adt.StructLit, a []ast.Decl) {
 	for _, d := range a {
+		c.markAlias(d)
+	}
+	for _, d := range a {
 		c.addLetDecl(d)
 	}
 	for _, d := range a {
@@ -450,6 +462,30 @@
 	}
 }
 
+func (c *compiler) markAlias(d ast.Decl) {
+	switch x := d.(type) {
+	case *ast.Field:
+		lab := x.Label
+		if a, ok := lab.(*ast.Alias); ok {
+			if _, ok = a.Expr.(ast.Label); !ok {
+				c.errf(a, "alias expression is not a valid label")
+			}
+
+			e := aliasEntry{source: a}
+
+			c.insertAlias(a.Ident, e)
+		}
+
+	case *ast.LetClause:
+		a := aliasEntry{source: x}
+		c.insertAlias(x.Ident, a)
+
+	case *ast.Alias:
+		a := aliasEntry{source: x}
+		c.insertAlias(x.Ident, a)
+	}
+}
+
 func (c *compiler) decl(d ast.Decl) adt.Decl {
 	switch x := d.(type) {
 	case *ast.BadDecl:
@@ -462,18 +498,12 @@
 				return c.errf(a, "alias expression is not a valid label")
 			}
 
-			e := aliasEntry{source: a}
-
 			switch lab.(type) {
 			case *ast.Ident, *ast.BasicLit, *ast.ListLit:
 				// Even though we won't need the alias, we still register it
 				// for duplicate and failed reference detection.
 			default:
-				e.expr = c.expr(a.Expr)
-			}
-
-			if err := c.insertAlias(a.Ident, e); err != nil {
-				return err
+				c.updateAlias(a.Ident, c.expr(a.Expr))
 			}
 		}
 
@@ -576,19 +606,13 @@
 		// blowup in x2: x1+x1, x3: x2+x2, ... patterns.
 
 		expr := c.labeledExpr(nil, (*letScope)(x), x.Expr)
-
-		a := aliasEntry{source: x, expr: expr}
-
-		c.insertAlias(x.Ident, a)
+		c.updateAlias(x.Ident, expr)
 
 	case *ast.Alias:
+		// TODO(legacy): deprecated, remove this use of Alias
 
 		expr := c.labeledExpr(nil, (*deprecatedAliasScope)(x), x.Expr)
-
-		// TODO(legacy): deprecated, remove this use of Alias
-		a := aliasEntry{source: x, expr: expr}
-
-		c.insertAlias(x.Ident, a)
+		c.updateAlias(x.Ident, expr)
 	}
 }