internal/core/eval: fix multi-conjunct pattern constraints

Change-Id: I9842281e9fbb8f004b8a17b90c479bc79f4e15f2
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/6703
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/testdata/eval/bulk.txtar b/cue/testdata/eval/bulk.txtar
index c32e0e0..dd0a305 100644
--- a/cue/testdata/eval/bulk.txtar
+++ b/cue/testdata/eval/bulk.txtar
@@ -12,8 +12,36 @@
 	}
 }
 
+t1: {
+  #a: {
+    [>"e" & <"z"]: int
+  }
+  b: #a & { f: 4 }
+  c: #a & { z: 4 }
+}
+
+t2: {
+  #a: {
+    ["x" | "y"]: int
+  }
+  b: #a & { x: 4 }
+  c: #a & { z: 4 }
+}
+
 -- out/eval --
-(struct){
+Errors:
+t1.c: field `z` not allowed:
+    ./in.cue:15:3
+    ./in.cue:15:7
+    ./in.cue:19:11
+t2.c: field `z` not allowed:
+    ./in.cue:23:3
+    ./in.cue:23:7
+    ./in.cue:27:11
+
+Result:
+(_|_){
+  // [eval]
   a: (struct){
     foo: (struct){
       a: (int){ 1 }
@@ -29,6 +57,36 @@
       name: (string){ "foobar" }
     }
   }
+  t1: (_|_){
+    // [eval]
+    #a: (#struct){
+    }
+    b: (#struct){
+      f: (int){ 4 }
+    }
+    c: (_|_){
+      // [eval] t1.c: field `z` not allowed:
+      //     ./in.cue:15:3
+      //     ./in.cue:15:7
+      //     ./in.cue:19:11
+      z: (int){ 4 }
+    }
+  }
+  t2: (_|_){
+    // [eval]
+    #a: (#struct){
+    }
+    b: (#struct){
+      x: (int){ 4 }
+    }
+    c: (_|_){
+      // [eval] t2.c: field `z` not allowed:
+      //     ./in.cue:23:3
+      //     ./in.cue:23:7
+      //     ./in.cue:27:11
+      z: (int){ 4 }
+    }
+  }
 }
 -- out/compile --
 --- in.cue
@@ -47,4 +105,26 @@
       c: 2
     }
   })
+  t1: {
+    #a: {
+      [(>"e" & <"z")]: int
+    }
+    b: (〈0;#a〉 & {
+      f: 4
+    })
+    c: (〈0;#a〉 & {
+      z: 4
+    })
+  }
+  t2: {
+    #a: {
+      [("x"|"y")]: int
+    }
+    b: (〈0;#a〉 & {
+      x: 4
+    })
+    c: (〈0;#a〉 & {
+      z: 4
+    })
+  }
 }
diff --git a/internal/core/eval/optionals.go b/internal/core/eval/optionals.go
index 3dc1884..0426c18 100644
--- a/internal/core/eval/optionals.go
+++ b/internal/core/eval/optionals.go
@@ -16,7 +16,9 @@
 
 // TODO: rename this file to fieldset.go
 
-import "cuelang.org/go/internal/core/adt"
+import (
+	"cuelang.org/go/internal/core/adt"
+)
 
 // fieldSet represents the fields for a single struct literal, along
 // the constraints of fields that may be added.
@@ -169,33 +171,22 @@
 		// TODO: handle dynamically
 		return
 	}
-	switch f := v.(type) {
-	case *adt.Num:
-		// Just assert an error. Lists have not been expanded yet at
-		// this point, so there is no need to check for existing
-		//fields.
-		l, err := adt.MakeLabel(x.Src, c.Int64(f), adt.IntLabel)
-		if err != nil {
-			c.AddErr(err)
-			return
-		}
-		o.bulk = append(o.bulk, bulkField{labelMatcher(l), x})
 
+	if m := o.getMatcher(c, v); m != nil {
+		o.bulk = append(o.bulk, bulkField{m, x})
+	}
+}
+
+func (o *fieldSet) getMatcher(c *adt.OpContext, v adt.Value) fieldMatcher {
+	switch f := v.(type) {
 	case *adt.Top:
-		o.bulk = append(o.bulk, bulkField{typeMatcher(adt.TopKind), x})
+		return typeMatcher(adt.TopKind)
 
 	case *adt.BasicType:
-		o.bulk = append(o.bulk, bulkField{typeMatcher(f.K), x})
-
-	case *adt.String:
-		l := c.Label(f)
-		o.bulk = append(o.bulk, bulkField{labelMatcher(l), x})
-
-	case adt.Validator:
-		o.bulk = append(o.bulk, bulkField{validateMatcher{f}, x})
+		return typeMatcher(f.K)
 
 	default:
-		// TODO(err): not allowed type
+		return o.newPatternMatcher(c, v)
 	}
 }
 
@@ -212,12 +203,6 @@
 	Match(c *adt.OpContext, f adt.Feature) bool
 }
 
-type labelMatcher adt.Feature
-
-func (m labelMatcher) Match(c *adt.OpContext, f adt.Feature) bool {
-	return adt.Feature(m) == f
-}
-
 type typeMatcher adt.Kind
 
 func (m typeMatcher) Match(c *adt.OpContext, f adt.Feature) bool {
@@ -231,15 +216,6 @@
 	return false
 }
 
-type validateMatcher struct {
-	adt.Validator
-}
-
-func (m validateMatcher) Match(c *adt.OpContext, f adt.Feature) bool {
-	v := f.ToValue(c)
-	return c.Validate(m.Validator, v) == nil
-}
-
 type dynamicMatcher struct {
 	env  *adt.Environment
 	expr adt.Expr
@@ -259,3 +235,20 @@
 	}
 	return f.SelectorString(c) == s.Str
 }
+
+type patternMatcher adt.Conjunct
+
+func (m patternMatcher) Match(c *adt.OpContext, f adt.Feature) bool {
+	v := adt.Vertex{}
+	v.AddConjunct(adt.Conjunct(m))
+	label := f.ToValue(c)
+	v.AddConjunct(adt.MakeConjunct(m.Env, label))
+	v.Finalize(c)
+	b, _ := v.Value.(*adt.Bottom)
+	return b == nil
+}
+
+func (o *fieldSet) newPatternMatcher(ctx *adt.OpContext, x adt.Value) fieldMatcher {
+	c := adt.MakeConjunct(o.env, x)
+	return patternMatcher(c)
+}