encoding/jsonschema: record more line information

Change-Id: I19e3f84623eadd2fe4b3811b3f6da6e6731f3a11
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/6300
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
Reviewed-by: Johan Euphrosine <proppy@google.com>
diff --git a/cmd/cue/cmd/testdata/script/def_jsonschema.txt b/cmd/cue/cmd/testdata/script/def_jsonschema.txt
index 3552938..612c064 100644
--- a/cmd/cue/cmd/testdata/script/def_jsonschema.txt
+++ b/cmd/cue/cmd/testdata/script/def_jsonschema.txt
@@ -70,7 +70,9 @@
 -- expect-stderr2 --
 age: conflicting values "twenty" and >=0 (mismatched types string and number):
     ./data.yaml:1:7
+    ./schema.json:19:18
 -- expect-stderr3 --
 age: conflicting values "twenty" and >=0 (mismatched types string and number):
     ./data.yaml:1:7
+    ./schema.json:19:18
 -- cue.mod --
diff --git a/encoding/jsonschema/constraints.go b/encoding/jsonschema/constraints.go
index a9260c6..d838d9c 100644
--- a/encoding/jsonschema/constraints.go
+++ b/encoding/jsonschema/constraints.go
@@ -203,12 +203,12 @@
 		for _, x := range s.listItems("enum", n, true) {
 			a = append(a, s.value(x))
 		}
-		s.addConjunct(ast.NewBinExpr(token.OR, a...))
+		s.addConjunct(n, ast.NewBinExpr(token.OR, a...))
 		s.typeOptional = true
 	}),
 
 	p1d("const", 6, func(n cue.Value, s *state) {
-		s.addConjunct(s.value(n))
+		s.addConjunct(n, s.value(n))
 	}),
 
 	p1("default", func(n cue.Value, s *state) {
@@ -268,7 +268,7 @@
 			expr = &ast.BadExpr{From: n.Pos()}
 		}
 
-		s.addConjunct(expr)
+		s.addConjunct(n, expr)
 	}),
 
 	// Combinators
@@ -360,22 +360,22 @@
 			return
 		}
 		s.usedTypes |= cue.StringKind
-		s.addConjunct(&ast.UnaryExpr{Op: token.MAT, X: s.string(n)})
+		s.addConjunct(n, &ast.UnaryExpr{Op: token.MAT, X: s.string(n)})
 	}),
 
 	p1("minLength", func(n cue.Value, s *state) {
 		s.usedTypes |= cue.StringKind
 		min := s.number(n)
-		strings := s.addImport("strings")
-		s.addConjunct(ast.NewCall(ast.NewSel(strings, "MinRunes"), min))
+		strings := s.addImport(n, "strings")
+		s.addConjunct(n, ast.NewCall(ast.NewSel(strings, "MinRunes"), min))
 
 	}),
 
 	p1("maxLength", func(n cue.Value, s *state) {
 		s.usedTypes |= cue.StringKind
 		max := s.number(n)
-		strings := s.addImport("strings")
-		s.addConjunct(ast.NewCall(ast.NewSel(strings, "MaxRunes"), max))
+		strings := s.addImport(n, "strings")
+		s.addConjunct(n, ast.NewCall(ast.NewSel(strings, "MaxRunes"), max))
 	}),
 
 	p1d("contentMediaType", 7, func(n cue.Value, s *state) {
@@ -396,24 +396,24 @@
 
 	p1("minimum", func(n cue.Value, s *state) {
 		s.usedTypes |= cue.NumberKind
-		s.addConjunct(&ast.UnaryExpr{Op: token.GEQ, X: s.number(n)})
+		s.addConjunct(n, &ast.UnaryExpr{Op: token.GEQ, X: s.number(n)})
 	}),
 
 	p1("exclusiveMinimum", func(n cue.Value, s *state) {
 		// TODO: should we support Draft 4 booleans?
 		s.usedTypes |= cue.NumberKind
-		s.addConjunct(&ast.UnaryExpr{Op: token.GTR, X: s.number(n)})
+		s.addConjunct(n, &ast.UnaryExpr{Op: token.GTR, X: s.number(n)})
 	}),
 
 	p1("maximum", func(n cue.Value, s *state) {
 		s.usedTypes |= cue.NumberKind
-		s.addConjunct(&ast.UnaryExpr{Op: token.LEQ, X: s.number(n)})
+		s.addConjunct(n, &ast.UnaryExpr{Op: token.LEQ, X: s.number(n)})
 	}),
 
 	p1("exclusiveMaximum", func(n cue.Value, s *state) {
 		// TODO: should we support Draft 4 booleans?
 		s.usedTypes |= cue.NumberKind
-		s.addConjunct(&ast.UnaryExpr{Op: token.LSS, X: s.number(n)})
+		s.addConjunct(n, &ast.UnaryExpr{Op: token.LSS, X: s.number(n)})
 	}),
 
 	p1("multipleOf", func(n cue.Value, s *state) {
@@ -424,8 +424,8 @@
 		if x.Cmp(big.NewInt(0)) != 1 {
 			s.errf(n, `"multipleOf" value must be < 0; found %s`, n)
 		}
-		math := s.addImport("math")
-		s.addConjunct(ast.NewCall(ast.NewSel(math, "MultipleOf"), multiple))
+		math := s.addImport(n, "math")
+		s.addConjunct(n, ast.NewCall(ast.NewSel(math, "MultipleOf"), multiple))
 	}),
 
 	// Object constraints
@@ -515,7 +515,7 @@
 		// [=~pattern]: _
 		if names, _ := s.schemaState(n, cue.StringKind, nil, false); !isAny(names) {
 			s.usedTypes |= cue.StructKind
-			s.addConjunct(ast.NewStruct(ast.NewList((names)), ast.NewIdent("_")))
+			s.addConjunct(n, ast.NewStruct(ast.NewList((names)), ast.NewIdent("_")))
 		}
 	}),
 
@@ -523,15 +523,15 @@
 	// p1("minProperties", func(n cue.Value, s *state) {
 	// 	s.usedTypes |= cue.StructKind
 
-	// 	pkg := s.addImport("struct")
-	// 	s.addConjunct(ast.NewCall(ast.NewSel(pkg, "MinFields"), s.uint(n)))
+	// 	pkg := s.addImport(n, "struct")
+	// 	s.addConjunct(n, ast.NewCall(ast.NewSel(pkg, "MinFields"), s.uint(n)))
 	// }),
 
 	p1("maxProperties", func(n cue.Value, s *state) {
 		s.usedTypes |= cue.StructKind
 
-		pkg := s.addImport("struct")
-		s.addConjunct(ast.NewCall(ast.NewSel(pkg, "MaxFields"), s.uint(n)))
+		pkg := s.addImport(n, "struct")
+		s.addConjunct(n, ast.NewCall(ast.NewSel(pkg, "MaxFields"), s.uint(n)))
 	}),
 
 	p1("dependencies", func(n cue.Value, s *state) {
@@ -616,7 +616,7 @@
 		case cue.StructKind:
 			elem := s.schema(n)
 			ast.SetRelPos(elem, token.NoRelPos)
-			s.addConjunct(ast.NewList(&ast.Ellipsis{Type: elem}))
+			s.addConjunct(n, ast.NewList(&ast.Ellipsis{Type: elem}))
 
 		case cue.ListKind:
 			var a []ast.Expr
@@ -626,7 +626,7 @@
 				a = append(a, v)
 			}
 			s.list = ast.NewList(a...)
-			s.addConjunct(s.list)
+			s.addConjunct(n, s.list)
 
 		default:
 			s.errf(n, `value of "items" must be an object or array`)
@@ -652,10 +652,10 @@
 
 	p1("contains", func(n cue.Value, s *state) {
 		s.usedTypes |= cue.ListKind
-		list := s.addImport("list")
+		list := s.addImport(n, "list")
 		// TODO: Passing non-concrete values is not yet supported in CUE.
 		if x := s.schema(n); !isAny(x) {
-			s.addConjunct(ast.NewCall(ast.NewSel(list, "Contains"), clearPos(x)))
+			s.addConjunct(n, ast.NewCall(ast.NewSel(list, "Contains"), clearPos(x)))
 		}
 	}),
 
@@ -671,24 +671,24 @@
 		for ; p > 0; p-- {
 			a = append(a, ast.NewIdent("_"))
 		}
-		s.addConjunct(ast.NewList(append(a, &ast.Ellipsis{})...))
+		s.addConjunct(n, ast.NewList(append(a, &ast.Ellipsis{})...))
 
 		// TODO: use this once constraint resolution is properly implemented.
-		// list := s.addImport("list")
-		// s.addConjunct(ast.NewCall(ast.NewSel(list, "MinItems"), clearPos(s.uint(n))))
+		// list := s.addImport(n, "list")
+		// s.addConjunct(n, ast.NewCall(ast.NewSel(list, "MinItems"), clearPos(s.uint(n))))
 	}),
 
 	p1("maxItems", func(n cue.Value, s *state) {
 		s.usedTypes |= cue.ListKind
-		list := s.addImport("list")
-		s.addConjunct(ast.NewCall(ast.NewSel(list, "MaxItems"), clearPos(s.uint(n))))
+		list := s.addImport(n, "list")
+		s.addConjunct(n, ast.NewCall(ast.NewSel(list, "MaxItems"), clearPos(s.uint(n))))
 	}),
 
 	p1("uniqueItems", func(n cue.Value, s *state) {
 		s.usedTypes |= cue.ListKind
 		if s.boolValue(n) {
-			list := s.addImport("list")
-			s.addConjunct(ast.NewCall(ast.NewSel(list, "UniqueItems")))
+			list := s.addImport(n, "list")
+			s.addConjunct(n, ast.NewCall(ast.NewSel(list, "UniqueItems")))
 		}
 	}),
 }
diff --git a/encoding/jsonschema/decode.go b/encoding/jsonschema/decode.go
index 302084e..20ffc73 100644
--- a/encoding/jsonschema/decode.go
+++ b/encoding/jsonschema/decode.go
@@ -46,7 +46,7 @@
 }
 
 // addImport registers
-func (d *decoder) addImport(pkg string) *ast.Ident {
+func (d *decoder) addImport(n cue.Value, pkg string) *ast.Ident {
 	spec := ast.NewImport(nil, pkg)
 	info, err := astutil.ParseImportSpec(spec)
 	if err != nil {
@@ -54,6 +54,7 @@
 	}
 	ident := ast.NewIdent(info.Ident)
 	ident.Node = spec
+	ast.SetPos(ident, n.Pos())
 
 	return ident
 }
@@ -405,8 +406,10 @@
 	}
 }
 
-func (s *state) addConjunct(e ast.Expr) {
+func (s *state) addConjunct(n cue.Value, e ast.Expr) {
 	if !isAny(e) {
+		ast.SetPos(e, n.Pos())
+		ast.SetRelPos(e, token.NoRelPos)
 		s.conjuncts = append(s.conjuncts, e)
 	}
 }