vendor: go get github.com/zclconf/go-cty@master

This fixes some consistency problems with how number strings were parsed
in the msgpack decoder vs other situations.

This commit also includes an upgrade of HCL2 to use this new cty function,
though there's no change in behavior here since the new function is
functionally equivalent to what it replaced.
This commit is contained in:
Martin Atkins 2019-01-24 15:12:57 -08:00
parent 514ac6b890
commit fb0c9714c1
9 changed files with 62 additions and 29 deletions

4
go.mod
View File

@ -72,7 +72,7 @@ require (
github.com/hashicorp/go-version v1.0.0 github.com/hashicorp/go-version v1.0.0
github.com/hashicorp/golang-lru v0.5.0 // indirect github.com/hashicorp/golang-lru v0.5.0 // indirect
github.com/hashicorp/hcl v1.0.0 github.com/hashicorp/hcl v1.0.0
github.com/hashicorp/hcl2 v0.0.0-20190116200548-7b147fbae47a github.com/hashicorp/hcl2 v0.0.0-20190124230628-a9ca194bcdc3
github.com/hashicorp/hil v0.0.0-20170627220502-fa9f258a9250 github.com/hashicorp/hil v0.0.0-20170627220502-fa9f258a9250
github.com/hashicorp/logutils v0.0.0-20150609070431-0dc08b1671f3 github.com/hashicorp/logutils v0.0.0-20150609070431-0dc08b1671f3
github.com/hashicorp/memberlist v0.1.0 // indirect github.com/hashicorp/memberlist v0.1.0 // indirect
@ -129,7 +129,7 @@ require (
github.com/xanzy/ssh-agent v0.2.0 github.com/xanzy/ssh-agent v0.2.0
github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18 // indirect github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18 // indirect
github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557 github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557
github.com/zclconf/go-cty v0.0.0-20181231001355-67e3da15e430 github.com/zclconf/go-cty v0.0.0-20190124225737-a385d646c1e9
go.opencensus.io v0.17.0 // indirect go.opencensus.io v0.17.0 // indirect
go.uber.org/atomic v1.3.2 // indirect go.uber.org/atomic v1.3.2 // indirect
go.uber.org/multierr v1.1.0 // indirect go.uber.org/multierr v1.1.0 // indirect

8
go.sum
View File

@ -162,8 +162,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/hcl2 v0.0.0-20181208003705-670926858200/go.mod h1:ShfpTh661oAaxo7VcNxg0zcZW6jvMa7Moy2oFx7e5dE= github.com/hashicorp/hcl2 v0.0.0-20181208003705-670926858200/go.mod h1:ShfpTh661oAaxo7VcNxg0zcZW6jvMa7Moy2oFx7e5dE=
github.com/hashicorp/hcl2 v0.0.0-20190116200548-7b147fbae47a h1:+RoIWXVNQ9PUkXCKvzE+PlMLU/O0PNI9ItPQ7A0KW88= github.com/hashicorp/hcl2 v0.0.0-20190124230628-a9ca194bcdc3 h1:z8jV6t+XwhZ6NR70Fm5Pf2kvDP25b8gFQwJb5ndsnV4=
github.com/hashicorp/hcl2 v0.0.0-20190116200548-7b147fbae47a/go.mod h1:ShfpTh661oAaxo7VcNxg0zcZW6jvMa7Moy2oFx7e5dE= github.com/hashicorp/hcl2 v0.0.0-20190124230628-a9ca194bcdc3/go.mod h1:HtEzazM5AZ9fviNEof8QZB4T1Vz9UhHrGhnMPzl//Ek=
github.com/hashicorp/hil v0.0.0-20170627220502-fa9f258a9250 h1:fooK5IvDL/KIsi4LxF/JH68nVdrBSiGNPhS2JAQjtjo= github.com/hashicorp/hil v0.0.0-20170627220502-fa9f258a9250 h1:fooK5IvDL/KIsi4LxF/JH68nVdrBSiGNPhS2JAQjtjo=
github.com/hashicorp/hil v0.0.0-20170627220502-fa9f258a9250/go.mod h1:KHvg/R2/dPtaePb16oW4qIyzkMxXOL38xjRN64adsts= github.com/hashicorp/hil v0.0.0-20170627220502-fa9f258a9250/go.mod h1:KHvg/R2/dPtaePb16oW4qIyzkMxXOL38xjRN64adsts=
github.com/hashicorp/logutils v0.0.0-20150609070431-0dc08b1671f3 h1:oD64EFjELI9RY9yoWlfua58r+etdnoIC871z+rr6lkA= github.com/hashicorp/logutils v0.0.0-20150609070431-0dc08b1671f3 h1:oD64EFjELI9RY9yoWlfua58r+etdnoIC871z+rr6lkA=
@ -323,8 +323,8 @@ github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q
github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557 h1:Jpn2j6wHkC9wJv5iMfJhKqrZJx3TahFx+7sbZ7zQdxs= github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557 h1:Jpn2j6wHkC9wJv5iMfJhKqrZJx3TahFx+7sbZ7zQdxs=
github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
github.com/zclconf/go-cty v0.0.0-20181129180422-88fbe721e0f8/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= github.com/zclconf/go-cty v0.0.0-20181129180422-88fbe721e0f8/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
github.com/zclconf/go-cty v0.0.0-20181231001355-67e3da15e430 h1:dVON7OSpamimAzArYpi0Zl/iuvrhGqPnP/OO+XHXofY= github.com/zclconf/go-cty v0.0.0-20190124225737-a385d646c1e9 h1:hHCAGde+QfwbqXSAqOmBd4NlOrJ6nmjWp+Nu408ezD4=
github.com/zclconf/go-cty v0.0.0-20181231001355-67e3da15e430/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= github.com/zclconf/go-cty v0.0.0-20190124225737-a385d646c1e9/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
go.opencensus.io v0.17.0 h1:2Cu88MYg+1LU+WVD+NWwYhyP0kKgRlN9QjWGaX0jKTE= go.opencensus.io v0.17.0 h1:2Cu88MYg+1LU+WVD+NWwYhyP0kKgRlN9QjWGaX0jKTE=
go.opencensus.io v0.17.0/go.mod h1:mp1VrMQxhlqqDpKvH4UcQUa4YwlzNmymAjPrDdfxNpI= go.opencensus.io v0.17.0/go.mod h1:mp1VrMQxhlqqDpKvH4UcQUa4YwlzNmymAjPrDdfxNpI=
go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4=

View File

@ -9,7 +9,6 @@ import (
"github.com/apparentlymart/go-textseg/textseg" "github.com/apparentlymart/go-textseg/textseg"
"github.com/hashicorp/hcl2/hcl" "github.com/hashicorp/hcl2/hcl"
"github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/convert"
) )
type parser struct { type parser struct {
@ -236,10 +235,18 @@ func (p *parser) finishParsingBodyAttribute(ident Token, singleLine bool) (Node,
end := p.Peek() end := p.Peek()
if end.Type != TokenNewline && end.Type != TokenEOF { if end.Type != TokenNewline && end.Type != TokenEOF {
if !p.recovery { if !p.recovery {
summary := "Missing newline after argument"
detail := "An argument definition must end with a newline."
if end.Type == TokenComma {
summary = "Unexpected comma after argument"
detail = "Argument definitions must be separated by newlines, not commas. " + detail
}
diags = append(diags, &hcl.Diagnostic{ diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError, Severity: hcl.DiagError,
Summary: "Missing newline after argument", Summary: summary,
Detail: "An argument definition must end with a newline.", Detail: detail,
Subject: &end.Range, Subject: &end.Range,
Context: hcl.RangeBetween(ident.Range, end.Range).Ptr(), Context: hcl.RangeBetween(ident.Range, end.Range).Ptr(),
}) })
@ -1040,11 +1047,10 @@ func (p *parser) parseExpressionTerm() (Expression, hcl.Diagnostics) {
} }
func (p *parser) numberLitValue(tok Token) (cty.Value, hcl.Diagnostics) { func (p *parser) numberLitValue(tok Token) (cty.Value, hcl.Diagnostics) {
// We'll lean on the cty converter to do the conversion, to ensure that // The cty.ParseNumberVal is always the same behavior as converting a
// the behavior is the same as what would happen if converting a // string to a number, ensuring we always interpret decimal numbers in
// non-literal string to a number. // the same way.
numStrVal := cty.StringVal(string(tok.Bytes)) numVal, err := cty.ParseNumberVal(string(tok.Bytes))
numVal, err := convert.Convert(numStrVal, cty.Number)
if err != nil { if err != nil {
ret := cty.UnknownVal(cty.Number) ret := cty.UnknownVal(cty.Number)
return ret, hcl.Diagnostics{ return ret, hcl.Diagnostics{

View File

@ -3,9 +3,9 @@ package json
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"math/big"
"github.com/hashicorp/hcl2/hcl" "github.com/hashicorp/hcl2/hcl"
"github.com/zclconf/go-cty/cty"
) )
func parseFileContent(buf []byte, filename string) (node, hcl.Diagnostics) { func parseFileContent(buf []byte, filename string) (node, hcl.Diagnostics) {
@ -370,10 +370,15 @@ func parseNumber(p *peeker) (node, hcl.Diagnostics) {
} }
} }
f, _, err := big.ParseFloat(string(num), 10, 512, big.ToNearestEven) // We want to guarantee that we parse numbers the same way as cty (and thus
// native syntax HCL) would here, so we'll use the cty parser even though
// in most other cases we don't actually introduce cty concepts until
// decoding time. We'll unwrap the parsed float immediately afterwards, so
// the cty value is just a temporary helper.
nv, err := cty.ParseNumberVal(string(num))
if err != nil { if err != nil {
// Should never happen if above passed, since JSON numbers are a subset // Should never happen if above passed, since JSON numbers are a subset
// of what big.Float can parse... // of what cty can parse...
return nil, hcl.Diagnostics{ return nil, hcl.Diagnostics{
{ {
Severity: hcl.DiagError, Severity: hcl.DiagError,
@ -385,7 +390,7 @@ func parseNumber(p *peeker) (node, hcl.Diagnostics) {
} }
return &numberVal{ return &numberVal{
Value: f, Value: nv.AsBigFloat(),
SrcRange: tok.Range, SrcRange: tok.Range,
}, nil }, nil
} }

View File

@ -1,8 +1,6 @@
package convert package convert
import ( import (
"math/big"
"github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty"
) )
@ -30,11 +28,11 @@ var primitiveConversionsSafe = map[cty.Type]map[cty.Type]conversion{
var primitiveConversionsUnsafe = map[cty.Type]map[cty.Type]conversion{ var primitiveConversionsUnsafe = map[cty.Type]map[cty.Type]conversion{
cty.String: { cty.String: {
cty.Number: func(val cty.Value, path cty.Path) (cty.Value, error) { cty.Number: func(val cty.Value, path cty.Path) (cty.Value, error) {
f, _, err := big.ParseFloat(val.AsString(), 10, 512, big.ToNearestEven) v, err := cty.ParseNumberVal(val.AsString())
if err != nil { if err != nil {
return cty.NilVal, path.NewErrorf("a number is required") return cty.NilVal, path.NewErrorf("a number is required")
} }
return cty.NumberVal(f), nil return v, nil
}, },
cty.Bool: func(val cty.Value, path cty.Path) (cty.Value, error) { cty.Bool: func(val cty.Value, path cty.Path) (cty.Value, error) {
switch val.AsString() { switch val.AsString() {

View File

@ -72,7 +72,7 @@ func unmarshalPrimitive(tok json.Token, t cty.Type, path cty.Path) (cty.Value, e
} }
switch v := tok.(type) { switch v := tok.(type) {
case string: case string:
val, err := convert.Convert(cty.StringVal(v), t) val, err := cty.ParseNumberVal(v)
if err != nil { if err != nil {
return cty.NilVal, path.NewError(err) return cty.NilVal, path.NewError(err)
} }

View File

@ -2,7 +2,6 @@ package msgpack
import ( import (
"bytes" "bytes"
"math/big"
"github.com/vmihailenco/msgpack" "github.com/vmihailenco/msgpack"
msgpackCodes "github.com/vmihailenco/msgpack/codes" msgpackCodes "github.com/vmihailenco/msgpack/codes"
@ -113,12 +112,11 @@ func unmarshalPrimitive(dec *msgpack.Decoder, ty cty.Type, path cty.Path) (cty.V
if err != nil { if err != nil {
return cty.DynamicVal, path.NewErrorf("number is required") return cty.DynamicVal, path.NewErrorf("number is required")
} }
bf := &big.Float{} v, err := cty.ParseNumberVal(rv)
_, _, err = bf.Parse(rv, 10)
if err != nil { if err != nil {
return cty.DynamicVal, path.NewErrorf("number is required") return cty.DynamicVal, path.NewErrorf("number is required")
} }
return cty.NumberVal(bf), nil return v, nil
} }
case cty.String: case cty.String:
rv, err := dec.DecodeString() rv, err := dec.DecodeString()

View File

@ -30,6 +30,32 @@ func NumberVal(v *big.Float) Value {
} }
} }
// ParseNumberVal returns a Value of type number produced by parsing the given
// string as a decimal real number. To ensure that two identical strings will
// always produce an equal number, always use this function to derive a number
// from a string; it will ensure that the precision and rounding mode for the
// internal big decimal is configured in a consistent way.
//
// If the given string cannot be parsed as a number, the returned error has
// the message "a number is required", making it suitable to return to an
// end-user to signal a type conversion error.
//
// If the given string contains a number that becomes a recurring fraction
// when expressed in binary then it will be truncated to have a 512-bit
// mantissa. Note that this is a higher precision than that of a float64,
// so coverting the same decimal number first to float64 and then calling
// NumberFloatVal will not produce an equal result; the conversion first
// to float64 will round the mantissa to fewer than 512 bits.
func ParseNumberVal(s string) (Value, error) {
// Base 10, precision 512, and rounding to nearest even is the standard
// way to handle numbers arriving as strings.
f, _, err := big.ParseFloat(s, 10, 512, big.ToNearestEven)
if err != nil {
return NilVal, fmt.Errorf("a number is required")
}
return NumberVal(f), nil
}
// NumberIntVal returns a Value of type Number whose internal value is equal // NumberIntVal returns a Value of type Number whose internal value is equal
// to the given integer. // to the given integer.
func NumberIntVal(v int64) Value { func NumberIntVal(v int64) Value {

4
vendor/modules.txt vendored
View File

@ -351,7 +351,7 @@ github.com/hashicorp/hcl/hcl/scanner
github.com/hashicorp/hcl/hcl/strconv github.com/hashicorp/hcl/hcl/strconv
github.com/hashicorp/hcl/json/scanner github.com/hashicorp/hcl/json/scanner
github.com/hashicorp/hcl/json/token github.com/hashicorp/hcl/json/token
# github.com/hashicorp/hcl2 v0.0.0-20190116200548-7b147fbae47a # github.com/hashicorp/hcl2 v0.0.0-20190124230628-a9ca194bcdc3
github.com/hashicorp/hcl2/hcl github.com/hashicorp/hcl2/hcl
github.com/hashicorp/hcl2/hcl/hclsyntax github.com/hashicorp/hcl2/hcl/hclsyntax
github.com/hashicorp/hcl2/hcldec github.com/hashicorp/hcl2/hcldec
@ -482,7 +482,7 @@ github.com/vmihailenco/msgpack/codes
github.com/xanzy/ssh-agent github.com/xanzy/ssh-agent
# github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557 # github.com/xlab/treeprint v0.0.0-20161029104018-1d6e34225557
github.com/xlab/treeprint github.com/xlab/treeprint
# github.com/zclconf/go-cty v0.0.0-20181231001355-67e3da15e430 # github.com/zclconf/go-cty v0.0.0-20190124225737-a385d646c1e9
github.com/zclconf/go-cty/cty github.com/zclconf/go-cty/cty
github.com/zclconf/go-cty/cty/gocty github.com/zclconf/go-cty/cty/gocty
github.com/zclconf/go-cty/cty/convert github.com/zclconf/go-cty/cty/convert