Repository: goplus/gop
Pull request #1515 (2023-11-02 15:18:33)

typesutil.SetErrorGo116


Patch:
diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml
index 21776fd5..2e288a65 100644
--- a/.github/workflows/release-build.yml
+++ b/.github/workflows/release-build.yml
@@ -22,7 +22,7 @@ jobs:
     - name: Set up Go
       uses: actions/setup-go@v4
       with:
-        go-version: 1.18
+        go-version: 1.17
 
     - name: Build
       run: |
diff --git a/parser/_instance/instance5/cmd.gop b/parser/_instance/instance5/cmd.gop
index e185d378..b693b560 100644
--- a/parser/_instance/instance5/cmd.gop
+++ b/parser/_instance/instance5/cmd.gop
@@ -1,11 +1,6 @@
 var a [2]int
-
 if 0 < a[0] {
 	println a
-	println M[int]{1}
-	println T[int]{a: 1, b: 2}
-}
-
-for _, i := range []int{7, 42} {
-	println i
+	println T[int]{1}
+	println (T[int]){a:1,b:2}
 }
diff --git a/parser/_instance/instance5/parser.expect b/parser/_instance/instance5/parser.expect
index fb6a2d13..1dc92068 100644
--- a/parser/_instance/instance5/parser.expect
+++ b/parser/_instance/instance5/parser.expect
@@ -70,7 +70,7 @@ ast.FuncDecl:
                             ast.IndexExpr:
                               X:
                                 ast.Ident:
-                                  Name: M
+                                  Name: T
                               Index:
                                 ast.Ident:
                                   Name: int
@@ -87,13 +87,15 @@ ast.FuncDecl:
                       Args:
                         ast.CompositeLit:
                           Type:
-                            ast.IndexExpr:
+                            ast.ParenExpr:
                               X:
-                                ast.Ident:
-                                  Name: T
-                              Index:
-                                ast.Ident:
-                                  Name: int
+                                ast.IndexExpr:
+                                  X:
+                                    ast.Ident:
+                                      Name: T
+                                  Index:
+                                    ast.Ident:
+                                      Name: int
                           Elts:
                             ast.KeyValueExpr:
                               Key:
@@ -111,37 +113,3 @@ ast.FuncDecl:
                                 ast.BasicLit:
                                   Kind: INT
                                   Value: 2
-        ast.RangeStmt:
-          Key:
-            ast.Ident:
-              Name: _
-          Value:
-            ast.Ident:
-              Name: i
-          Tok: :=
-          X:
-            ast.CompositeLit:
-              Type:
-                ast.ArrayType:
-                  Elt:
-                    ast.Ident:
-                      Name: int
-              Elts:
-                ast.BasicLit:
-                  Kind: INT
-                  Value: 7
-                ast.BasicLit:
-                  Kind: INT
-                  Value: 42
-          Body:
-            ast.BlockStmt:
-              List:
-                ast.ExprStmt:
-                  X:
-                    ast.CallExpr:
-                      Fun:
-                        ast.Ident:
-                          Name: println
-                      Args:
-                        ast.Ident:
-                          Name: i
diff --git a/parser/parser.go b/parser/parser.go
index ef1d8a64..5914f55b 100644
--- a/parser/parser.go
+++ b/parser/parser.go
@@ -2068,6 +2068,29 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
 	return x
 }
 
+// isLiteralType reports whether x is a legal composite literal type.
+func isLiteralType(x ast.Expr) bool {
+	switch t := unparen(x).(type) {
+	case *ast.BadExpr:
+	case *ast.Ident:
+	case *ast.IndexExpr:
+		_, isIdent := t.X.(*ast.Ident)
+		return isIdent
+	case *ast.IndexListExpr:
+		_, isIdent := t.X.(*ast.Ident)
+		return isIdent
+	case *ast.SelectorExpr:
+		_, isIdent := t.X.(*ast.Ident)
+		return isIdent
+	case *ast.ArrayType:
+	case *ast.StructType:
+	case *ast.MapType:
+	default:
+		return false // all other nodes are not legal composite literal types
+	}
+	return true
+}
+
 /*
 // If x is of the form *T, deref returns T, otherwise it returns x.
 func deref(x ast.Expr) ast.Expr {
@@ -2151,30 +2174,13 @@ L:
 		case token.LBRACE: // {
 			if allowCmd && p.isCmd(x) { // println {...}
 				x = p.parseCallOrConversion(p.checkExprOrType(x), true)
-			} else {
-				t := unparen(x)
-				// determine if '{' belongs to a composite literal or a block statement
-				switch t.(type) {
-				case *ast.BadExpr, *ast.Ident, *ast.SelectorExpr:
-					if p.exprLev < 0 {
-						break L
-					}
-					// x is possibly a composite literal type
-				case *ast.IndexExpr, *ast.IndexListExpr:
-					if p.exprLev < 0 {
-						break L
-					}
-					// x is possibly a composite literal type
-				case *ast.ArrayType, *ast.StructType, *ast.MapType:
-					// x is a composite literal type
-				default:
-					break L
-				}
-				if t != x {
-					p.error(t.Pos(), "cannot parenthesize type in composite literal")
-					// already progressed, no need to advance
+			} else if isLiteralType(x) && p.exprLev >= 0 {
+				if lhs {
+					p.resolve(x)
 				}
 				x = p.parseLiteralValue(x)
+			} else {
+				break L
 			}
 		case token.NOT:
 			if allowCmd && p.isCmd(x) {
@@ -3641,9 +3647,6 @@ func (p *parser) parseGlobalStmts(sync map[token.Token]bool, pos token.Pos, stmt
 	if p.errors.Len() != 0 { // TODO: error
 		p.advance(sync)
 	}
-	if p.tok != token.EOF {
-		p.errorExpected(p.pos, "statement", 2)
-	}
 	f := &ast.FuncDecl{
 		Name: &ast.Ident{NamePos: pos, Name: "main"},
 		Doc:  doc,
diff --git a/x/typesutil/check.go b/x/typesutil/check.go
index 71f8ec47..9690da11 100644
--- a/x/typesutil/check.go
+++ b/x/typesutil/check.go
@@ -207,20 +207,26 @@ func (p *Checker) Files(goFiles []*goast.File, gopFiles []*ast.File) (err error)
 	return
 }
 
-func convErr(fset *token.FileSet, e error) (*types.Error, bool) {
+func convErr(fset *token.FileSet, e error) (ret *types.Error, ok bool) {
 	switch v := e.(type) {
 	case *gox.CodeError:
-		return &types.Error{Fset: fset, Pos: v.Pos, Msg: v.Msg}, true
+		ret = &types.Error{Fset: fset, Pos: v.Pos, Msg: v.Msg}
+		typesutil.SetErrorGo116(ret, 0, v.Pos, v.Pos)
 	case *gox.MatchError:
-		pos := token.NoPos
+		pos, end := token.NoPos, token.NoPos
 		if v.Src != nil {
-			pos = v.Src.Pos()
+			pos, end = v.Src.Pos(), v.Src.End()
 		}
-		return &types.Error{Fset: fset, Pos: pos, Msg: v.Message("")}, true
+		ret = &types.Error{Fset: fset, Pos: pos, Msg: v.Message("")}
+		typesutil.SetErrorGo116(ret, 0, pos, end)
 	case *gox.ImportError:
-		return &types.Error{Fset: fset, Pos: v.Pos, Msg: v.Err.Error()}, true
+		ret = &types.Error{Fset: fset, Pos: v.Pos, Msg: v.Err.Error()}
+		typesutil.SetErrorGo116(ret, 0, v.Pos, v.Pos)
+	default:
+		return
 	}
-	return nil, false
+	ok = true
+	return
 }
 
 func scopeDelete(objMap map[types.Object]types.Object, scope *types.Scope, name string) {
diff --git a/x/typesutil/internal/typesutil/types.go b/x/typesutil/internal/typesutil/types.go
index 2835c371..45c1f02d 100644
--- a/x/typesutil/internal/typesutil/types.go
+++ b/x/typesutil/internal/typesutil/types.go
@@ -22,6 +22,8 @@ import (
 	"unsafe"
 )
 
+// -----------------------------------------------------------------------------
+
 // A Scope maintains a set of objects and links to its containing
 // (parent) and contained (children) scopes. Objects may be inserted
 // and looked up by name. The zero value for Scope is a ready-to-use
@@ -45,3 +47,45 @@ func ScopeDelete(s *types.Scope, name string) types.Object {
 	}
 	return nil
 }
+
+// -----------------------------------------------------------------------------
+
+// An Error describes a type-checking error; it implements the error interface.
+// A "soft" error is an error that still permits a valid interpretation of a
+// package (such as "unused variable"); "hard" errors may lead to unpredictable
+// behavior if ignored.
+type Error struct {
+	Fset *token.FileSet // file set for interpretation of Pos
+	Pos  token.Pos      // error position
+	Msg  string         // error message
+	Soft bool           // if set, error is "soft"
+
+	// go116code is a future API, unexported as the set of error codes is large
+	// and likely to change significantly during experimentation. Tools wishing
+	// to preview this feature may read go116code using reflection (see
+	// errorcodes_test.go), but beware that there is no guarantee of future
+	// compatibility.
+	go116code  int
+	go116start token.Pos
+	go116end   token.Pos
+}
+
+func SetErrorGo116(ret *types.Error, code int, start, end token.Pos) {
+	e := (*Error)(unsafe.Pointer(ret))
+	e.go116code = code
+	e.go116start = start
+	e.go116end = end
+}
+
+// -----------------------------------------------------------------------------
+
+func init() {
+	if unsafe.Sizeof(Scope{}) != unsafe.Sizeof(types.Scope{}) {
+		panic("unexpected sizeof types.Scope")
+	}
+	if unsafe.Sizeof(Error{}) != unsafe.Sizeof(types.Error{}) {
+		panic("unexpected sizeof types.Error")
+	}
+}
+
+// -----------------------------------------------------------------------------


Test patch:
diff --git a/parser/parser_test.go b/parser/parser_test.go
index a387edc4..76fe912d 100644
--- a/parser/parser_test.go
+++ b/parser/parser_test.go
@@ -508,14 +508,4 @@ const d
 `, `/foo/bar.gox:5:7: missing constant value`, ``)
 }
 
-func TestErrGlobal(t *testing.T) {
-	testErrCode(t, `func test() {}
-}`, `/foo/bar.gop:2:1: expected statement, found '}'`, ``)
-}
-
-func TestErrCompositeLiteral(t *testing.T) {
-	testErrCode(t, `println (T[int]){a: 1, b: 2}
-`, `/foo/bar.gop:1:10: cannot parenthesize type in composite literal`, ``)
-}
-
 // -----------------------------------------------------------------------------