internal/core/adt: control fixes for if clauses

A left-over omission to support embedded scalars.

First, treat comprehensions as embedded for scalars.

This also adjust some control flow issues. As we now associate
nodeContext with the node, there is more of a reliance on
states progressing monotonically. So Partial should not be
set too early, nor is this necessary.

Fixes #729
Fixes #739

Change-Id: If283f3ec47532ecac8237c1df1931abb5cbe98a6
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/8662
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Paul Jolly <paul@myitcv.org.uk>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/testdata/cycle/issue429.txtar b/cue/testdata/cycle/issue429.txtar
index 8b9ddb6..b5e0154 100644
--- a/cue/testdata/cycle/issue429.txtar
+++ b/cue/testdata/cycle/issue429.txtar
@@ -71,9 +71,6 @@
 es3.max: invalid value 5 (out of bound >10):
     ./in.cue:5:10
     ./in.cue:22:10
-er3.min: invalid value 5 (out of bound <5):
-    ./in.cue:29:10
-    ./in.cue:44:10
 er3.max: invalid value 5 (out of bound >5):
     ./in.cue:30:10
     ./in.cue:45:10
@@ -155,9 +152,9 @@
       //     ./in.cue:28:11
       //     ./in.cue:43:6
       //     ./in.cue:44:10
-      // er3.min: invalid value 5 (out of bound <5):
-      //     ./in.cue:29:10
-      //     ./in.cue:44:10
+      // er3.max: invalid value 5 (out of bound >5):
+      //     ./in.cue:30:10
+      //     ./in.cue:45:10
     }
     max: (_|_){
       // [eval] er3.max: invalid value 5 (out of bound >5):
diff --git a/cue/testdata/scalars/embed.txtar b/cue/testdata/scalars/embed.txtar
index e25ba14..86089e5 100644
--- a/cue/testdata/scalars/embed.txtar
+++ b/cue/testdata/scalars/embed.txtar
@@ -1,3 +1,5 @@
+// Issue ##739
+
 -- in.cue --
 import "strings"
 
@@ -67,6 +69,30 @@
     b: a.#def
 }
 
+optionalExists: {
+    string | {
+        value?: string
+
+        if value != _|_ {
+            other: int
+        }
+    }
+}
+
+optionalCheck: {
+    thing: string | {
+        value?: string
+
+        if value != _|_ {
+            other: int
+        }
+    }
+
+    thing: {
+        value: "some string"
+        other: 3
+    }
+}
 -- out/eval --
 Errors:
 listEmbed.b6: invalid list index 5 (out of bounds):
@@ -160,6 +186,14 @@
     }
     b: (int){ 1 }
   }
+  optionalExists: ((string|struct)){ |((string){ string }, (struct){
+    }) }
+  optionalCheck: (struct){
+    thing: (struct){
+      value: (string){ "some string" }
+      other: (int){ 3 }
+    }
+  }
 }
 -- out/compile --
 --- in.cue
@@ -247,4 +281,24 @@
     }
     b: 〈0;a〉.#def
   }
+  optionalExists: {
+    (string|{
+      value?: string
+      if (〈0;value〉 != _|_(explicit error (_|_ literal) in source)) {
+        other: int
+      }
+    })
+  }
+  optionalCheck: {
+    thing: (string|{
+      value?: string
+      if (〈0;value〉 != _|_(explicit error (_|_ literal) in source)) {
+        other: int
+      }
+    })
+    thing: {
+      value: "some string"
+      other: 3
+    }
+  }
 }
diff --git a/cue/testdata/scalars/yield.txtar b/cue/testdata/scalars/yield.txtar
new file mode 100644
index 0000000..5f0e41e
--- /dev/null
+++ b/cue/testdata/scalars/yield.txtar
@@ -0,0 +1,75 @@
+// Issue #729
+-- in.cue --
+ifScalar: {
+    _#cond: true
+
+    if _#cond {5}
+}
+
+ifScalarConflict: {
+    _#cond: true
+
+    if _#cond {5}
+
+    "soo"
+}
+
+ifScalarNested: {
+    _#cond: true
+
+    if _#cond {{{5}}}
+
+}
+-- out/eval --
+Errors:
+ifScalarConflict: conflicting values "soo" and 5 (mismatched types string and int):
+    ./in.cue:10:5
+    ./in.cue:10:16
+    ./in.cue:12:5
+
+Result:
+(_|_){
+  // [eval]
+  ifScalar: (int){
+    5
+    _#cond: (bool){ true }
+  }
+  ifScalarConflict: (_|_){
+    // [eval] ifScalarConflict: conflicting values "soo" and 5 (mismatched types string and int):
+    //     ./in.cue:10:5
+    //     ./in.cue:10:16
+    //     ./in.cue:12:5
+    _#cond: (bool){ true }
+  }
+  ifScalarNested: (int){
+    5
+    _#cond: (bool){ true }
+  }
+}
+-- out/compile --
+--- in.cue
+{
+  ifScalar: {
+    _#cond: true
+    if 〈0;_#cond〉 {
+      5
+    }
+  }
+  ifScalarConflict: {
+    _#cond: true
+    if 〈0;_#cond〉 {
+      5
+    }
+    "soo"
+  }
+  ifScalarNested: {
+    _#cond: true
+    if 〈0;_#cond〉 {
+      {
+        {
+          5
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/internal/core/adt/disjunct.go b/internal/core/adt/disjunct.go
index bb31c03..8d538a8 100644
--- a/internal/core/adt/disjunct.go
+++ b/internal/core/adt/disjunct.go
@@ -416,11 +416,6 @@
 				copy(a.Conjuncts, arc.Conjuncts)
 
 			default:
-				// This should never happen and would be a performance issue.
-				// But try to mend the situation by doing something sensible in
-				// case the user is not running with strict mode enabled.
-				Assertf(false, "invalid state for disjunct")
-
 				a := *arc
 				a.state = arc.state.clone()
 				a.state.node = &a
diff --git a/internal/core/adt/eval.go b/internal/core/adt/eval.go
index 8ca30c3..addd784 100644
--- a/internal/core/adt/eval.go
+++ b/internal/core/adt/eval.go
@@ -1076,7 +1076,7 @@
 		return
 	}
 	if n.scalar != nil {
-		n.node.SetValue(n.ctx, Partial, n.scalar)
+		n.node.BaseValue = n.scalar
 	}
 	// NOTE: this is now handled by associating the nodeContext
 	// if n.errs != nil {
diff --git a/internal/core/adt/expr.go b/internal/core/adt/expr.go
index d4130ce..5c40ae3 100644
--- a/internal/core/adt/expr.go
+++ b/internal/core/adt/expr.go
@@ -117,6 +117,7 @@
 			o.HasEmbed = true
 
 		case *ForClause, Yielder:
+			o.HasEmbed = true
 
 		case *BulkOptionalField:
 			o.Bulk = append(o.Bulk, x)