]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile/internal/types2: correct error position for inherited...
authorRobert Griesemer <gri@golang.org>
Fri, 4 Dec 2020 21:20:06 +0000 (13:20 -0800)
committerRobert Griesemer <gri@golang.org>
Mon, 7 Dec 2020 16:44:07 +0000 (16:44 +0000)
Enabled fixedbugs/issue8183.go for run.go with new typechecker
now that issue is fixed.

Fixes #42992.
Updates #42991.

Change-Id: I23451999983b740d5f37ce3fa75ee756daf1a44f
Reviewed-on: https://go-review.googlesource.com/c/go/+/275517
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/types2/check.go
src/cmd/compile/internal/types2/decl.go
src/cmd/compile/internal/types2/errors.go
src/cmd/compile/internal/types2/resolver.go
src/cmd/compile/internal/types2/testdata/constdecl.src
test/fixedbugs/issue8183.go
test/run.go

index 45045865451b45499cafa7cd50dd1c8f791fda79..6ba8506916f4b49ca292655b109d3fe93f5850fb 100644 (file)
@@ -51,6 +51,7 @@ type context struct {
        scope         *Scope                    // top-most scope for lookups
        pos           syntax.Pos                // if valid, identifiers are looked up as if at position pos (used by Eval)
        iota          constant.Value            // value of iota in a constant declaration; nil otherwise
+       errpos        syntax.Pos                // if valid, identifier position of a constant with inherited initializer
        sig           *Signature                // function signature if inside a function; nil otherwise
        isPanic       map[*syntax.CallExpr]bool // set of panic call expressions (used for termination check)
        hasLabel      bool                      // set if a function makes use of labels (only ~1% of functions); unused outside functions
index bb33e38051942ca6a0a95c64f37eb9aa0f11b25d..bc3e665b711fe079450c51669a65c5c664ebe8dd 100644 (file)
@@ -187,7 +187,7 @@ func (check *Checker) objDecl(obj Object, def *Named) {
        switch obj := obj.(type) {
        case *Const:
                check.decl = d // new package-level const decl
-               check.constDecl(obj, d.vtyp, d.init)
+               check.constDecl(obj, d.vtyp, d.init, d.inherited)
        case *Var:
                check.decl = d // new package-level var decl
                check.varDecl(obj, d.lhs, d.vtyp, d.init)
@@ -421,12 +421,16 @@ func firstInSrc(path []Object) int {
        return fst
 }
 
-func (check *Checker) constDecl(obj *Const, typ, init syntax.Expr) {
+func (check *Checker) constDecl(obj *Const, typ, init syntax.Expr, inherited bool) {
        assert(obj.typ == nil)
 
-       // use the correct value of iota
-       defer func(iota constant.Value) { check.iota = iota }(check.iota)
+       // use the correct value of iota and errpos
+       defer func(iota constant.Value, errpos syntax.Pos) {
+               check.iota = iota
+               check.errpos = errpos
+       }(check.iota, check.errpos)
        check.iota = obj.val
+       check.errpos = nopos
 
        // provide valid constant value under all circumstances
        obj.val = constant.MakeUnknown()
@@ -449,6 +453,15 @@ func (check *Checker) constDecl(obj *Const, typ, init syntax.Expr) {
        // check initialization
        var x operand
        if init != nil {
+               if inherited {
+                       // The initialization expression is inherited from a previous
+                       // constant declaration, and (error) positions refer to that
+                       // expression and not the current constant declaration. Use
+                       // the constant identifier position for any errors during
+                       // init expression evaluation since that is all we have
+                       // (see issues #42991, #42992).
+                       check.errpos = obj.pos
+               }
                check.expr(&x, init)
        }
        check.initConst(obj, &x)
@@ -898,7 +911,7 @@ func (check *Checker) declStmt(list []syntax.Decl) {
                                        init = values[i]
                                }
 
-                               check.constDecl(obj, last.Type, init)
+                               check.constDecl(obj, last.Type, init, inherited)
                        }
 
                        // Constants must always have init values.
index 07f9aad48b6b23e74b8b5948e612d85521dc28f1..941e7c6fd36a5ca5331fc7a0ae12f73c16f7f9a2 100644 (file)
@@ -87,6 +87,17 @@ func (check *Checker) err(pos syntax.Pos, msg string, soft bool) {
                return
        }
 
+       // If we are encountering an error while evaluating an inherited
+       // constant initialization expression, pos is the position of in
+       // the original expression, and not of the currently declared
+       // constant identifier. Use the provided errpos instead.
+       // TODO(gri) We may also want to augment the error message and
+       // refer to the position (pos) in the original expression.
+       if check.errpos.IsKnown() {
+               assert(check.iota != nil)
+               pos = check.errpos
+       }
+
        err := Error{pos, stripAnnotations(msg), msg, soft}
        if check.firstErr == nil {
                check.firstErr = err
index b116888bf239115acc5d6c3712adadd235d5838c..cf9893ca87478857ce6940136a257a0104b05ed6 100644 (file)
@@ -17,12 +17,13 @@ import (
 
 // A declInfo describes a package-level const, type, var, or func declaration.
 type declInfo struct {
-       file  *Scope           // scope of file containing this declaration
-       lhs   []*Var           // lhs of n:1 variable declarations, or nil
-       vtyp  syntax.Expr      // type, or nil (for const and var declarations only)
-       init  syntax.Expr      // init/orig expression, or nil (for const and var declarations only)
-       tdecl *syntax.TypeDecl // type declaration, or nil
-       fdecl *syntax.FuncDecl // func declaration, or nil
+       file      *Scope           // scope of file containing this declaration
+       lhs       []*Var           // lhs of n:1 variable declarations, or nil
+       vtyp      syntax.Expr      // type, or nil (for const and var declarations only)
+       init      syntax.Expr      // init/orig expression, or nil (for const and var declarations only)
+       inherited bool             // if set, the init expression is inherited from a previous constant declaration
+       tdecl     *syntax.TypeDecl // type declaration, or nil
+       fdecl     *syntax.FuncDecl // func declaration, or nil
 
        // The deps field tracks initialization expression dependencies.
        deps map[Object]bool // lazily initialized
@@ -338,7 +339,7 @@ func (check *Checker) collectObjects() {
                                                init = values[i]
                                        }
 
-                                       d := &declInfo{file: fileScope, vtyp: last.Type, init: init}
+                                       d := &declInfo{file: fileScope, vtyp: last.Type, init: init, inherited: inherited}
                                        check.declarePkgObj(name, obj, d)
                                }
 
index e9a5162e9ce093a2e31606232628ec7924b9029a..1a7ed003a4c3574db72f8bf3b3423c323c7e0a79 100644 (file)
@@ -104,4 +104,35 @@ func _() {
        const x, y, z = 0, 1, unsafe.Sizeof(func() { _ = x /* ERROR "undeclared name" */ + y /* ERROR "undeclared name" */ + z /* ERROR "undeclared name" */ })
 }
 
+// Test cases for errors in inherited constant initialization expressions.
+// Errors related to inherited initialization expressions must appear at
+// the constant identifier being declared, not at the original expression
+// (issues #42991, #42992).
+const (
+       _ byte = 255 + iota
+       /* some gap */
+       _ // ERROR overflows byte
+       /* some gap */
+       /* some gap */ _ /* ERROR overflows byte */; _ /* ERROR overflows byte */
+       /* some gap */
+       _ = 255 + iota
+       _ = byte /* ERROR overflows byte */ (255) + iota
+       _ /* ERROR overflows byte */
+)
+
+// Test cases from issue.
+const (
+       ok = byte(iota + 253)
+       bad
+       barn
+       bard // ERROR cannot convert
+)
+
+const (
+       c = len([1 - iota]int{})
+       d
+       e // ERROR invalid array length
+       f // ERROR invalid array length
+)
+
 // TODO(gri) move extra tests from testdata/const0.src into here
index 531dd4dbf854cb828c03467364a9a5a7a41004ee..01954dd107ea4a75c9bbd536ae77f585707cfafd 100644 (file)
@@ -12,12 +12,12 @@ const (
        ok = byte(iota + 253)
        bad
        barn
-       bard // ERROR "constant 256 overflows byte"
+       bard // ERROR "constant 256 overflows byte|cannot convert"
 )
 
 const (
        c = len([1 - iota]int{})
        d
-       e // ERROR "array bound must be non-negative"
-       f // ERROR "array bound must be non-negative"
+       e // ERROR "array bound must be non-negative|invalid array length"
+       f // ERROR "array bound must be non-negative|invalid array length"
 )
index 0ffb2c1a3da0fbe343148a3f772a99ea11d4cd81..a3e2ac5e32969570b34b095939d16278a25f9d06 100644 (file)
@@ -2132,5 +2132,4 @@ var excluded = map[string]bool{
        "fixedbugs/issue7746.go":   true, // type-checking doesn't terminate
        "fixedbugs/issue8501.go":   true, // crashes
        "fixedbugs/issue8507.go":   true, // crashes
-       "fixedbugs/issue8183.go":   true, // issue #42992
 }