1
0
mirror of https://github.com/golang/go synced 2024-11-26 20:21:25 -07:00

go/types, types2: don't verify infer result if no Config.Error is given

With no error handler installed, an error leads to an (internal panic
and) immediate abort of type checking. Not all invariants hold up in
this case, but it also doesn't matter.

In Checker.infer, verify result conditions always if an error handler
is installed, but only then.

Fixes #61938.

Change-Id: I4d3d61bbccc696a75639fee5010f5d3cef17e855
Reviewed-on: https://go-review.googlesource.com/c/go/+/519775
Reviewed-by: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@google.com>
This commit is contained in:
Robert Griesemer 2023-08-15 14:17:02 -07:00 committed by Gopher Robot
parent f2f5979253
commit 294e1b260e
4 changed files with 42 additions and 2 deletions

View File

@ -27,7 +27,11 @@ const enableReverseTypeInference = true // disable for debugging
// If successful, infer returns the complete list of given and inferred type arguments, one for each // If successful, infer returns the complete list of given and inferred type arguments, one for each
// type parameter. Otherwise the result is nil and appropriate errors will be reported. // type parameter. Otherwise the result is nil and appropriate errors will be reported.
func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type, params *Tuple, args []*operand) (inferred []Type) { func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type, params *Tuple, args []*operand) (inferred []Type) {
if debug { // Don't verify result conditions if there's no error handler installed:
// in that case, an error leads to an exit panic and the result value may
// be incorrect. But in that case it doesn't matter because callers won't
// be able to use it either.
if check.conf.Error != nil {
defer func() { defer func() {
assert(inferred == nil || len(inferred) == len(tparams) && !containsNil(inferred)) assert(inferred == nil || len(inferred) == len(tparams) && !containsNil(inferred))
}() }()

View File

@ -920,3 +920,19 @@ func _() {
var conf Config var conf Config
conf.Check(f.PkgName.Value, []*syntax.File{f}, nil) // must not panic conf.Check(f.PkgName.Value, []*syntax.File{f}, nil) // must not panic
} }
func TestIssue61938(t *testing.T) {
const src = `
package p
func f[T any]() {}
func _() { f() }
`
// no error handler provided (this issue)
var conf Config
typecheck(src, &conf, nil) // must not panic
// with error handler (sanity check)
conf.Error = func(error) {}
typecheck(src, &conf, nil) // must not panic
}

View File

@ -29,7 +29,11 @@ const enableReverseTypeInference = true // disable for debugging
// If successful, infer returns the complete list of given and inferred type arguments, one for each // If successful, infer returns the complete list of given and inferred type arguments, one for each
// type parameter. Otherwise the result is nil and appropriate errors will be reported. // type parameter. Otherwise the result is nil and appropriate errors will be reported.
func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type, params *Tuple, args []*operand) (inferred []Type) { func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type, params *Tuple, args []*operand) (inferred []Type) {
if debug { // Don't verify result conditions if there's no error handler installed:
// in that case, an error leads to an exit panic and the result value may
// be incorrect. But in that case it doesn't matter because callers won't
// be able to use it either.
if check.conf.Error != nil {
defer func() { defer func() {
assert(inferred == nil || len(inferred) == len(tparams) && !containsNil(inferred)) assert(inferred == nil || len(inferred) == len(tparams) && !containsNil(inferred))
}() }()

View File

@ -930,3 +930,19 @@ func _() {
var conf Config var conf Config
conf.Check(f.Name.Name, fset, []*ast.File{f}, nil) // must not panic conf.Check(f.Name.Name, fset, []*ast.File{f}, nil) // must not panic
} }
func TestIssue61938(t *testing.T) {
const src = `
package p
func f[T any]() {}
func _() { f() }
`
// no error handler provided (this issue)
var conf Config
typecheck(src, &conf, nil) // must not panic
// with error handler (sanity check)
conf.Error = func(error) {}
typecheck(src, &conf, nil) // must not panic
}