From 0fc3b127a09ee5f99f4f9f9a83d3364ff2b69a9b Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 4 Sep 2024 18:06:50 -0700 Subject: [PATCH] go/types, types2: factor type checking of basic literals and generate go/types code Move the code for type checking of basic literals into literals.go. In go/types, the respective code is now generated from the types2 source. Change-Id: Ib21eb7a87e11b77bcb2469985f9844964d35df57 Reviewed-on: https://go-review.googlesource.com/c/go/+/610540 LUCI-TryBot-Result: Go LUCI Reviewed-by: Robert Griesemer Reviewed-by: Tim King Auto-Submit: Robert Griesemer --- src/cmd/compile/internal/types2/expr.go | 58 +----------------- src/cmd/compile/internal/types2/literals.go | 67 +++++++++++++++++++- src/go/types/expr.go | 58 +----------------- src/go/types/generate_test.go | 5 +- src/go/types/literals.go | 68 ++++++++++++++++++++- 5 files changed, 139 insertions(+), 117 deletions(-) diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index a1e3012bcb..18524dde23 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -12,7 +12,6 @@ import ( "go/constant" "go/token" . "internal/types/errors" - "strings" ) /* @@ -1033,35 +1032,6 @@ func (check *Checker) nonGeneric(T *target, x *operand) { } } -// langCompat reports an error if the representation of a numeric -// literal is not compatible with the current language version. -func (check *Checker) langCompat(lit *syntax.BasicLit) { - s := lit.Value - if len(s) <= 2 || check.allowVersion(lit, go1_13) { - return - } - // len(s) > 2 - if strings.Contains(s, "_") { - check.versionErrorf(lit, go1_13, "underscore in numeric literal") - return - } - if s[0] != '0' { - return - } - radix := s[1] - if radix == 'b' || radix == 'B' { - check.versionErrorf(lit, go1_13, "binary literal") - return - } - if radix == 'o' || radix == 'O' { - check.versionErrorf(lit, go1_13, "0o/0O-style octal literal") - return - } - if lit.Kind != syntax.IntLit && (radix == 'x' || radix == 'X') { - check.versionErrorf(lit, go1_13, "hexadecimal floating-point literal") - } -} - // exprInternal contains the core of type checking of expressions. // Must only be called by rawExpr. // (See rawExpr for an explanation of the parameters.) @@ -1091,36 +1061,10 @@ func (check *Checker) exprInternal(T *target, x *operand, e syntax.Expr, hint Ty if e.Bad { goto Error // error reported during parsing } - switch e.Kind { - case syntax.IntLit, syntax.FloatLit, syntax.ImagLit: - check.langCompat(e) - // The max. mantissa precision for untyped numeric values - // is 512 bits, or 4048 bits for each of the two integer - // parts of a fraction for floating-point numbers that are - // represented accurately in the go/constant package. - // Constant literals that are longer than this many bits - // are not meaningful; and excessively long constants may - // consume a lot of space and time for a useless conversion. - // Cap constant length with a generous upper limit that also - // allows for separators between all digits. - const limit = 10000 - if len(e.Value) > limit { - check.errorf(e, InvalidConstVal, "excessively long constant: %s... (%d chars)", e.Value[:10], len(e.Value)) - goto Error - } - } - x.setConst(e.Kind, e.Value) + check.basicLit(x, e) if x.mode == invalid { - // The parser already establishes syntactic correctness. - // If we reach here it's because of number under-/overflow. - // TODO(gri) setConst (and in turn the go/constant package) - // should return an error describing the issue. - check.errorf(e, InvalidConstVal, "malformed constant: %s", e.Value) goto Error } - // Ensure that integer values don't overflow (go.dev/issue/54280). - x.expr = e // make sure that check.overflow below has an error position - check.overflow(x, opPos(x.expr)) case *syntax.FuncLit: check.funcLit(x, e) diff --git a/src/cmd/compile/internal/types2/literals.go b/src/cmd/compile/internal/types2/literals.go index 188c920776..1b47015ae2 100644 --- a/src/cmd/compile/internal/types2/literals.go +++ b/src/cmd/compile/internal/types2/literals.go @@ -2,15 +2,80 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// This file implements typechecking of composite literals. +// This file implements typechecking of literals. package types2 import ( "cmd/compile/internal/syntax" . "internal/types/errors" + "strings" ) +// langCompat reports an error if the representation of a numeric +// literal is not compatible with the current language version. +func (check *Checker) langCompat(lit *syntax.BasicLit) { + s := lit.Value + if len(s) <= 2 || check.allowVersion(lit, go1_13) { + return + } + // len(s) > 2 + if strings.Contains(s, "_") { + check.versionErrorf(lit, go1_13, "underscore in numeric literal") + return + } + if s[0] != '0' { + return + } + radix := s[1] + if radix == 'b' || radix == 'B' { + check.versionErrorf(lit, go1_13, "binary literal") + return + } + if radix == 'o' || radix == 'O' { + check.versionErrorf(lit, go1_13, "0o/0O-style octal literal") + return + } + if lit.Kind != syntax.IntLit && (radix == 'x' || radix == 'X') { + check.versionErrorf(lit, go1_13, "hexadecimal floating-point literal") + } +} + +func (check *Checker) basicLit(x *operand, e *syntax.BasicLit) { + switch e.Kind { + case syntax.IntLit, syntax.FloatLit, syntax.ImagLit: + check.langCompat(e) + // The max. mantissa precision for untyped numeric values + // is 512 bits, or 4048 bits for each of the two integer + // parts of a fraction for floating-point numbers that are + // represented accurately in the go/constant package. + // Constant literals that are longer than this many bits + // are not meaningful; and excessively long constants may + // consume a lot of space and time for a useless conversion. + // Cap constant length with a generous upper limit that also + // allows for separators between all digits. + const limit = 10000 + if len(e.Value) > limit { + check.errorf(e, InvalidConstVal, "excessively long constant: %s... (%d chars)", e.Value[:10], len(e.Value)) + x.mode = invalid + return + } + } + x.setConst(e.Kind, e.Value) + if x.mode == invalid { + // The parser already establishes syntactic correctness. + // If we reach here it's because of number under-/overflow. + // TODO(gri) setConst (and in turn the go/constant package) + // should return an error describing the issue. + check.errorf(e, InvalidConstVal, "malformed constant: %s", e.Value) + x.mode = invalid + return + } + // Ensure that integer values don't overflow (go.dev/issue/54280). + x.expr = e // make sure that check.overflow below has an error position + check.overflow(x, opPos(x.expr)) +} + func (check *Checker) funcLit(x *operand, e *syntax.FuncLit) { if sig, ok := check.typ(e.Type).(*Signature); ok { // Set the Scope's extent to the complete "func (...) {...}" diff --git a/src/go/types/expr.go b/src/go/types/expr.go index f742263455..eb97c89436 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -13,7 +13,6 @@ import ( "go/internal/typeparams" "go/token" . "internal/types/errors" - "strings" ) /* @@ -1027,35 +1026,6 @@ func (check *Checker) nonGeneric(T *target, x *operand) { } } -// langCompat reports an error if the representation of a numeric -// literal is not compatible with the current language version. -func (check *Checker) langCompat(lit *ast.BasicLit) { - s := lit.Value - if len(s) <= 2 || check.allowVersion(lit, go1_13) { - return - } - // len(s) > 2 - if strings.Contains(s, "_") { - check.versionErrorf(lit, go1_13, "underscore in numeric literal") - return - } - if s[0] != '0' { - return - } - radix := s[1] - if radix == 'b' || radix == 'B' { - check.versionErrorf(lit, go1_13, "binary literal") - return - } - if radix == 'o' || radix == 'O' { - check.versionErrorf(lit, go1_13, "0o/0O-style octal literal") - return - } - if lit.Kind != token.INT && (radix == 'x' || radix == 'X') { - check.versionErrorf(lit, go1_13, "hexadecimal floating-point literal") - } -} - // exprInternal contains the core of type checking of expressions. // Must only be called by rawExpr. // (See rawExpr for an explanation of the parameters.) @@ -1079,36 +1049,10 @@ func (check *Checker) exprInternal(T *target, x *operand, e ast.Expr, hint Type) goto Error case *ast.BasicLit: - switch e.Kind { - case token.INT, token.FLOAT, token.IMAG: - check.langCompat(e) - // The max. mantissa precision for untyped numeric values - // is 512 bits, or 4048 bits for each of the two integer - // parts of a fraction for floating-point numbers that are - // represented accurately in the go/constant package. - // Constant literals that are longer than this many bits - // are not meaningful; and excessively long constants may - // consume a lot of space and time for a useless conversion. - // Cap constant length with a generous upper limit that also - // allows for separators between all digits. - const limit = 10000 - if len(e.Value) > limit { - check.errorf(e, InvalidConstVal, "excessively long constant: %s... (%d chars)", e.Value[:10], len(e.Value)) - goto Error - } - } - x.setConst(e.Kind, e.Value) + check.basicLit(x, e) if x.mode == invalid { - // The parser already establishes syntactic correctness. - // If we reach here it's because of number under-/overflow. - // TODO(gri) setConst (and in turn the go/constant package) - // should return an error describing the issue. - check.errorf(e, InvalidConstVal, "malformed constant: %s", e.Value) goto Error } - // Ensure that integer values don't overflow (go.dev/issue/54280). - x.expr = e // make sure that check.overflow below has an error position - check.overflow(x, opPos(x.expr)) case *ast.FuncLit: check.funcLit(x, e) diff --git a/src/go/types/generate_test.go b/src/go/types/generate_test.go index 1422d1ae7c..62e17a957a 100644 --- a/src/go/types/generate_test.go +++ b/src/go/types/generate_test.go @@ -137,8 +137,11 @@ var filemap = map[string]action{ "instantiate.go": func(f *ast.File) { fixTokenPos(f); fixCheckErrorfCall(f) }, "instantiate_test.go": func(f *ast.File) { renameImportPath(f, `"cmd/compile/internal/types2"->"go/types"`) }, "literals.go": func(f *ast.File) { + insertImportPath(f, `"go/token"`) renameImportPath(f, `"cmd/compile/internal/syntax"->"go/ast"`) - renameSelectorExprs(f, "syntax.Name->ast.Ident", "key.Value->key.Name", "atyp.Elem->atyp.Elt") // must happen before renaming identifiers + renameSelectorExprs(f, + "syntax.IntLit->token.INT", "syntax.FloatLit->token.FLOAT", "syntax.ImagLit->token.IMAG", + "syntax.Name->ast.Ident", "key.Value->key.Name", "atyp.Elem->atyp.Elt") // must happen before renaming identifiers renameIdents(f, "syntax->ast") renameSelectors(f, "ElemList->Elts") }, diff --git a/src/go/types/literals.go b/src/go/types/literals.go index 5efb0360ad..0945eed153 100644 --- a/src/go/types/literals.go +++ b/src/go/types/literals.go @@ -5,15 +5,81 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// This file implements typechecking of composite literals. +// This file implements typechecking of literals. package types import ( "go/ast" + "go/token" . "internal/types/errors" + "strings" ) +// langCompat reports an error if the representation of a numeric +// literal is not compatible with the current language version. +func (check *Checker) langCompat(lit *ast.BasicLit) { + s := lit.Value + if len(s) <= 2 || check.allowVersion(lit, go1_13) { + return + } + // len(s) > 2 + if strings.Contains(s, "_") { + check.versionErrorf(lit, go1_13, "underscore in numeric literal") + return + } + if s[0] != '0' { + return + } + radix := s[1] + if radix == 'b' || radix == 'B' { + check.versionErrorf(lit, go1_13, "binary literal") + return + } + if radix == 'o' || radix == 'O' { + check.versionErrorf(lit, go1_13, "0o/0O-style octal literal") + return + } + if lit.Kind != token.INT && (radix == 'x' || radix == 'X') { + check.versionErrorf(lit, go1_13, "hexadecimal floating-point literal") + } +} + +func (check *Checker) basicLit(x *operand, e *ast.BasicLit) { + switch e.Kind { + case token.INT, token.FLOAT, token.IMAG: + check.langCompat(e) + // The max. mantissa precision for untyped numeric values + // is 512 bits, or 4048 bits for each of the two integer + // parts of a fraction for floating-point numbers that are + // represented accurately in the go/constant package. + // Constant literals that are longer than this many bits + // are not meaningful; and excessively long constants may + // consume a lot of space and time for a useless conversion. + // Cap constant length with a generous upper limit that also + // allows for separators between all digits. + const limit = 10000 + if len(e.Value) > limit { + check.errorf(e, InvalidConstVal, "excessively long constant: %s... (%d chars)", e.Value[:10], len(e.Value)) + x.mode = invalid + return + } + } + x.setConst(e.Kind, e.Value) + if x.mode == invalid { + // The parser already establishes syntactic correctness. + // If we reach here it's because of number under-/overflow. + // TODO(gri) setConst (and in turn the go/constant package) + // should return an error describing the issue. + check.errorf(e, InvalidConstVal, "malformed constant: %s", e.Value) + x.mode = invalid + return + } + // Ensure that integer values don't overflow (go.dev/issue/54280). + x.expr = e // make sure that check.overflow below has an error position + check.overflow(x, opPos(x.expr)) +} + func (check *Checker) funcLit(x *operand, e *ast.FuncLit) { if sig, ok := check.typ(e.Type).(*Signature); ok { // Set the Scope's extent to the complete "func (...) {...}" -- 2.48.1