// Issue ##739

-- in.cue --
import "strings"
import "list"

intEmbed: {
	a1: {
		2
	}
	a2: {
		v: {
			3
			#foo: a2.v + 1
		}
		w: v
		x: v.#foo
	}
	a3: a1 + a2.v
}

listEmbed: {
	a1: {
		2
	}
	b3: {
		[1, 2]
		#foo: 1
	}
	b4: list.Concat([b3, b3])
	b5: b3[1]
	b6: b3[5]
	b7: b4[a1] // 1
}

stringEmbed: {
	s1: {
		"foo"
		#bar: "bar"
	}
	s2: [ s1, {s1.#bar, #baz: 4}]
	s3: strings.Join(s2, "--")
}

outPattern: {
	sum: {
		out: #a + #b
		#a:  int
		#b:  int
	}
	used: sum & {#a: 1, #b: 3}
}

arithmetic: {
	sum: {
		#a + #b
		#a: int
		#b: int
	}
	a1: (sum & {_, #a:          1, #b: 3}) + 2
	a2: 2 + (sum & {_, #a:      1, #b: 3})
	a3: 2 + (2 + (sum & {_, #a: 1, #b: 3}))
}

defCheck: {
	a: {
		#def: 1
	}
	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
	}
}

hidden: {
	issue794: {
		_foo: "foo"
		[_foo]
	}
}

-- issue2113.cue --
// In all these tests, embedded scalars should resolve without error.
merged: t1: p1: {
	#fn: { #in2: _, _ }
	#fn: { #in2: c1: string, #in2.c1 }
	x: #fn & {#in2: {c1: "V 1"}, _}
}
merged: t1: p2: {
	#fn: { #in2: c1: string, #in2.c1 }
	#fn: { #in2: _, _ }
	x: #fn & {#in2: {c1: "V 1"}, _}
}
merged: t1: p3: {
	x: #fn & {#in2: {c1: "V 1"}, _}
	#fn: { #in2: c1: string, #in2.c1 }
	#fn: { #in2: _, _ }
}
merged: t2: p1: {
	#fn: { #in2: {}, _ }
	#fn: { #in2: c1: string, #in2.c1 }
	x: #fn & {#in2: {c1: "V 1"}, _}
}
merged: t2: p2: {
	#fn: { #in2: c1: string, #in2.c1 }
	#fn: { #in2: {}, _ }
	x: #fn & {#in2: {c1: "V 1"}, _}
}
merged: t2: p3: {
	x: #fn & {#in2: {c1: "V 1"}, _}
	#fn: { #in2: c1: string, #in2.c1 }
	#fn: { #in2: {}, _ }
}

-- issue2163.cue --
selfRefInEmbed: t1: {
	#Func: {
		#in: _
		_
	}
	#fn: #Func
	#fn: {
		#in: _
	
		(#Func & {
			_foo: #in
			"buzz"
		}) + "fiz"
	}
}

-- out/eval/stats --
Leaks:  10
Freed:  130
Reused: 123
Allocs: 17
Retain: 57

Unifications: 136
Conjuncts:    304
Disjuncts:    173
-- out/evalalpha --
Errors:
listEmbed.b6: index out of range [5] with length 2:
    ./in.cue:29:9

Result:
(_|_){
  // [eval]
  intEmbed: (struct){
    a1: (int){ 2 }
    a2: (struct){
      v: (int){
        3
        #foo: (int){ 4 }
      }
      w: ~(intEmbed.a2.v)
      x: (int){ 4 }
    }
    a3: (int){ 5 }
  }
  listEmbed: (_|_){
    // [eval]
    a1: (int){ 2 }
    b3: (#list){
      #foo: (int){ 1 }
      0: (int){ 1 }
      1: (int){ 2 }
    }
    b4: (#list){
      0: (int){ 1 }
      1: (int){ 2 }
      2: (int){ 1 }
      3: (int){ 2 }
    }
    b5: (int){ 2 }
    b6: (_|_){
      // [eval] listEmbed.b6: index out of range [5] with length 2:
      //     ./in.cue:29:9
    }
    b7: (int){ 1 }
  }
  stringEmbed: (struct){
    s1: (string){
      "foo"
      #bar: (string){ "bar" }
    }
    s2: (#list){
      0: ~(stringEmbed.s1)
      1: (string){
        "bar"
        #baz: (int){ 4 }
      }
    }
    s3: (string){ "foo--bar" }
  }
  outPattern: (struct){
    sum: (struct){
      out: (_|_){
        // [incomplete] outPattern.sum.out: non-concrete value int in operand to +:
        //     ./in.cue:44:8
        //     ./in.cue:45:8
      }
      #a: (int){ int }
      #b: (int){ int }
    }
    used: (struct){
      #a: (int){ 1 }
      #b: (int){ 3 }
      out: (int){ 4 }
    }
  }
  arithmetic: (struct){
    sum: (_|_){
      // [incomplete] arithmetic.sum: non-concrete value int in operand to +:
      //     ./in.cue:53:3
      //     ./in.cue:54:7
      #a: (int){ int }
      #b: (int){ int }
    }
    a1: (int){ 6 }
    a2: (int){ 6 }
    a3: (int){ 8 }
  }
  defCheck: (struct){
    a: (struct){
      #def: (int){ 1 }
    }
    b: (int){ 1 }
  }
  optionalExists: ((string|struct)){ |((string){ string }, (struct){
      value?: (string){ string }
    }) }
  optionalCheck: (struct){
    thing: (struct){
      value: (string){ "some string" }
      other: (int){ 3 }
    }
  }
  hidden: (struct){
    issue794: (#list){
      _foo: (string){ "foo" }
      0: (string){ "foo" }
    }
  }
  merged: (struct){
    t1: (struct){
      p1: (struct){
        #fn: (string){
          string
          #in2: (#struct){
            c1: (string){ string }
          }
        }
        x: (string){
          "V 1"
          #in2: (#struct){
            c1: (string){ "V 1" }
          }
        }
      }
      p2: (struct){
        #fn: (string){
          string
          #in2: (#struct){
            c1: (string){ string }
          }
        }
        x: (string){
          "V 1"
          #in2: (#struct){
            c1: (string){ "V 1" }
          }
        }
      }
      p3: (struct){
        x: (string){
          "V 1"
          #in2: (#struct){
            c1: (string){ "V 1" }
          }
        }
        #fn: (string){
          string
          #in2: (#struct){
            c1: (string){ string }
          }
        }
      }
    }
    t2: (struct){
      p1: (struct){
        #fn: (string){
          string
          #in2: (#struct){
            c1: (string){ string }
          }
        }
        x: (string){
          "V 1"
          #in2: (#struct){
            c1: (string){ "V 1" }
          }
        }
      }
      p2: (struct){
        #fn: (string){
          string
          #in2: (#struct){
            c1: (string){ string }
          }
        }
        x: (string){
          "V 1"
          #in2: (#struct){
            c1: (string){ "V 1" }
          }
        }
      }
      p3: (struct){
        x: (string){
          "V 1"
          #in2: (#struct){
            c1: (string){ "V 1" }
          }
        }
        #fn: (string){
          string
          #in2: (#struct){
            c1: (string){ string }
          }
        }
      }
    }
  }
  selfRefInEmbed: (struct){
    t1: (struct){
      #Func: (_){
        _
        #in: (_){ _ }
      }
      #fn: (string){
        "buzzfiz"
        #in: (_){ _ }
      }
    }
  }
}
-- diff/-out/evalalpha<==>+out/eval --
diff old new
--- old
+++ new
@@ -1,5 +1,5 @@
 Errors:
-listEmbed.b6: invalid list index 5 (out of bounds):
+listEmbed.b6: index out of range [5] with length 2:
     ./in.cue:29:9
 
 Result:
@@ -12,10 +12,7 @@
         3
         #foo: (int){ 4 }
       }
-      w: (int){
-        3
-        #foo: (int){ 4 }
-      }
+      w: ~(intEmbed.a2.v)
       x: (int){ 4 }
     }
     a3: (int){ 5 }
@@ -36,7 +33,7 @@
     }
     b5: (int){ 2 }
     b6: (_|_){
-      // [eval] listEmbed.b6: invalid list index 5 (out of bounds):
+      // [eval] listEmbed.b6: index out of range [5] with length 2:
       //     ./in.cue:29:9
     }
     b7: (int){ 1 }
@@ -47,10 +44,7 @@
       #bar: (string){ "bar" }
     }
     s2: (#list){
-      0: (string){
-        "foo"
-        #bar: (string){ "bar" }
-      }
+      0: ~(stringEmbed.s1)
       1: (string){
         "bar"
         #baz: (int){ 4 }
@@ -69,9 +63,9 @@
       #b: (int){ int }
     }
     used: (struct){
-      out: (int){ 4 }
       #a: (int){ 1 }
       #b: (int){ 3 }
+      out: (int){ 4 }
     }
   }
   arithmetic: (struct){
-- diff/todo/p3 --
Reordering.
-- diff/explanation --
Improved error message.
-- out/eval --
Errors:
listEmbed.b6: invalid list index 5 (out of bounds):
    ./in.cue:29:9

Result:
(_|_){
  // [eval]
  intEmbed: (struct){
    a1: (int){ 2 }
    a2: (struct){
      v: (int){
        3
        #foo: (int){ 4 }
      }
      w: (int){
        3
        #foo: (int){ 4 }
      }
      x: (int){ 4 }
    }
    a3: (int){ 5 }
  }
  listEmbed: (_|_){
    // [eval]
    a1: (int){ 2 }
    b3: (#list){
      #foo: (int){ 1 }
      0: (int){ 1 }
      1: (int){ 2 }
    }
    b4: (#list){
      0: (int){ 1 }
      1: (int){ 2 }
      2: (int){ 1 }
      3: (int){ 2 }
    }
    b5: (int){ 2 }
    b6: (_|_){
      // [eval] listEmbed.b6: invalid list index 5 (out of bounds):
      //     ./in.cue:29:9
    }
    b7: (int){ 1 }
  }
  stringEmbed: (struct){
    s1: (string){
      "foo"
      #bar: (string){ "bar" }
    }
    s2: (#list){
      0: (string){
        "foo"
        #bar: (string){ "bar" }
      }
      1: (string){
        "bar"
        #baz: (int){ 4 }
      }
    }
    s3: (string){ "foo--bar" }
  }
  outPattern: (struct){
    sum: (struct){
      out: (_|_){
        // [incomplete] outPattern.sum.out: non-concrete value int in operand to +:
        //     ./in.cue:44:8
        //     ./in.cue:45:8
      }
      #a: (int){ int }
      #b: (int){ int }
    }
    used: (struct){
      out: (int){ 4 }
      #a: (int){ 1 }
      #b: (int){ 3 }
    }
  }
  arithmetic: (struct){
    sum: (_|_){
      // [incomplete] arithmetic.sum: non-concrete value int in operand to +:
      //     ./in.cue:53:3
      //     ./in.cue:54:7
      #a: (int){ int }
      #b: (int){ int }
    }
    a1: (int){ 6 }
    a2: (int){ 6 }
    a3: (int){ 8 }
  }
  defCheck: (struct){
    a: (struct){
      #def: (int){ 1 }
    }
    b: (int){ 1 }
  }
  optionalExists: ((string|struct)){ |((string){ string }, (struct){
      value?: (string){ string }
    }) }
  optionalCheck: (struct){
    thing: (struct){
      value: (string){ "some string" }
      other: (int){ 3 }
    }
  }
  hidden: (struct){
    issue794: (#list){
      _foo: (string){ "foo" }
      0: (string){ "foo" }
    }
  }
  merged: (struct){
    t1: (struct){
      p1: (struct){
        #fn: (string){
          string
          #in2: (#struct){
            c1: (string){ string }
          }
        }
        x: (string){
          "V 1"
          #in2: (#struct){
            c1: (string){ "V 1" }
          }
        }
      }
      p2: (struct){
        #fn: (string){
          string
          #in2: (#struct){
            c1: (string){ string }
          }
        }
        x: (string){
          "V 1"
          #in2: (#struct){
            c1: (string){ "V 1" }
          }
        }
      }
      p3: (struct){
        x: (string){
          "V 1"
          #in2: (#struct){
            c1: (string){ "V 1" }
          }
        }
        #fn: (string){
          string
          #in2: (#struct){
            c1: (string){ string }
          }
        }
      }
    }
    t2: (struct){
      p1: (struct){
        #fn: (string){
          string
          #in2: (#struct){
            c1: (string){ string }
          }
        }
        x: (string){
          "V 1"
          #in2: (#struct){
            c1: (string){ "V 1" }
          }
        }
      }
      p2: (struct){
        #fn: (string){
          string
          #in2: (#struct){
            c1: (string){ string }
          }
        }
        x: (string){
          "V 1"
          #in2: (#struct){
            c1: (string){ "V 1" }
          }
        }
      }
      p3: (struct){
        x: (string){
          "V 1"
          #in2: (#struct){
            c1: (string){ "V 1" }
          }
        }
        #fn: (string){
          string
          #in2: (#struct){
            c1: (string){ string }
          }
        }
      }
    }
  }
  selfRefInEmbed: (struct){
    t1: (struct){
      #Func: (_){
        _
        #in: (_){ _ }
      }
      #fn: (string){
        "buzzfiz"
        #in: (_){ _ }
      }
    }
  }
}
-- out/compile --
--- in.cue
{
  intEmbed: {
    a1: {
      2
    }
    a2: {
      v: {
        3
        #foo: (〈2;a2〉.v + 1)
      }
      w: 〈0;v〉
      x: 〈0;v〉.#foo
    }
    a3: (〈0;a1〉 + 〈0;a2〉.v)
  }
  listEmbed: {
    a1: {
      2
    }
    b3: {
      [
        1,
        2,
      ]
      #foo: 1
    }
    b4: 〈import;list〉.Concat([
      〈1;b3〉,
      〈1;b3〉,
    ])
    b5: 〈0;b3〉[1]
    b6: 〈0;b3〉[5]
    b7: 〈0;b4〉[〈0;a1〉]
  }
  stringEmbed: {
    s1: {
      "foo"
      #bar: "bar"
    }
    s2: [
      〈1;s1〉,
      {
        〈2;s1〉.#bar
        #baz: 4
      },
    ]
    s3: 〈import;strings〉.Join(〈0;s2〉, "--")
  }
  outPattern: {
    sum: {
      out: (〈0;#a〉 + 〈0;#b〉)
      #a: int
      #b: int
    }
    used: (〈0;sum〉 & {
      #a: 1
      #b: 3
    })
  }
  arithmetic: {
    sum: {
      (〈0;#a〉 + 〈0;#b〉)
      #a: int
      #b: int
    }
    a1: ((〈0;sum〉 & {
      _
      #a: 1
      #b: 3
    }) + 2)
    a2: (2 + (〈0;sum〉 & {
      _
      #a: 1
      #b: 3
    }))
    a3: (2 + (2 + (〈0;sum〉 & {
      _
      #a: 1
      #b: 3
    })))
  }
  defCheck: {
    a: {
      #def: 1
    }
    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
    }
  }
  hidden: {
    issue794: {
      _foo: "foo"
      [
        〈1;_foo〉,
      ]
    }
  }
}
--- issue2113.cue
{
  merged: {
    t1: {
      p1: {
        #fn: {
          #in2: _
          _
        }
        #fn: {
          #in2: {
            c1: string
          }
          〈0;#in2〉.c1
        }
        x: (〈0;#fn〉 & {
          #in2: {
            c1: "V 1"
          }
          _
        })
      }
    }
  }
  merged: {
    t1: {
      p2: {
        #fn: {
          #in2: {
            c1: string
          }
          〈0;#in2〉.c1
        }
        #fn: {
          #in2: _
          _
        }
        x: (〈0;#fn〉 & {
          #in2: {
            c1: "V 1"
          }
          _
        })
      }
    }
  }
  merged: {
    t1: {
      p3: {
        x: (〈0;#fn〉 & {
          #in2: {
            c1: "V 1"
          }
          _
        })
        #fn: {
          #in2: {
            c1: string
          }
          〈0;#in2〉.c1
        }
        #fn: {
          #in2: _
          _
        }
      }
    }
  }
  merged: {
    t2: {
      p1: {
        #fn: {
          #in2: {}
          _
        }
        #fn: {
          #in2: {
            c1: string
          }
          〈0;#in2〉.c1
        }
        x: (〈0;#fn〉 & {
          #in2: {
            c1: "V 1"
          }
          _
        })
      }
    }
  }
  merged: {
    t2: {
      p2: {
        #fn: {
          #in2: {
            c1: string
          }
          〈0;#in2〉.c1
        }
        #fn: {
          #in2: {}
          _
        }
        x: (〈0;#fn〉 & {
          #in2: {
            c1: "V 1"
          }
          _
        })
      }
    }
  }
  merged: {
    t2: {
      p3: {
        x: (〈0;#fn〉 & {
          #in2: {
            c1: "V 1"
          }
          _
        })
        #fn: {
          #in2: {
            c1: string
          }
          〈0;#in2〉.c1
        }
        #fn: {
          #in2: {}
          _
        }
      }
    }
  }
}
--- issue2163.cue
{
  selfRefInEmbed: {
    t1: {
      #Func: {
        #in: _
        _
      }
      #fn: 〈0;#Func〉
      #fn: {
        #in: _
        ((〈1;#Func〉 & {
          _foo: 〈1;#in〉
          "buzz"
        }) + "fiz")
      }
    }
  }
}
