From 294e1b260e8fe29d44dad615f6dbf064309d6228 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 15 Aug 2023 14:17:02 -0700 Subject: [PATCH] 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 Run-TryBot: Robert Griesemer Auto-Submit: Robert Griesemer TryBot-Result: Gopher Robot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/infer.go | 6 +++++- src/cmd/compile/internal/types2/issues_test.go | 16 ++++++++++++++++ src/go/types/infer.go | 6 +++++- src/go/types/issues_test.go | 16 ++++++++++++++++ 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go index 44d66eb516..e817210479 100644 --- a/src/cmd/compile/internal/types2/infer.go +++ b/src/cmd/compile/internal/types2/infer.go @@ -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 // 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) { - 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() { assert(inferred == nil || len(inferred) == len(tparams) && !containsNil(inferred)) }() diff --git a/src/cmd/compile/internal/types2/issues_test.go b/src/cmd/compile/internal/types2/issues_test.go index 9f67ad0902..bcebc2f2c0 100644 --- a/src/cmd/compile/internal/types2/issues_test.go +++ b/src/cmd/compile/internal/types2/issues_test.go @@ -920,3 +920,19 @@ func _() { var conf Config 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 +} diff --git a/src/go/types/infer.go b/src/go/types/infer.go index 7c7898435b..387695c16c 100644 --- a/src/go/types/infer.go +++ b/src/go/types/infer.go @@ -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 // 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) { - 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() { assert(inferred == nil || len(inferred) == len(tparams) && !containsNil(inferred)) }() diff --git a/src/go/types/issues_test.go b/src/go/types/issues_test.go index 64e1c20d7e..bdc1a388d8 100644 --- a/src/go/types/issues_test.go +++ b/src/go/types/issues_test.go @@ -930,3 +930,19 @@ func _() { var conf Config 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 +}