From 2c6f24c825aa91632a286ac34603d970f7a9f2f5 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 29 Jan 2024 16:34:16 -0800 Subject: [PATCH] go/types, types2: bail early if we want a type but don't have one If we do know whether we need a type or not, make use of the information when we know that we don't have a type and bail out. Fixes the issue at hand and also improves some other error messages which now report that we don't have a type instead of reporting a cycle. For #65344. Change-Id: I11182efd452c485d89e6c09ead8a647ea05d7318 Reviewed-on: https://go-review.googlesource.com/c/go/+/559335 Run-TryBot: Robert Griesemer Auto-Submit: Robert Griesemer Reviewed-by: Robert Findley Reviewed-by: Robert Griesemer TryBot-Bypass: Robert Griesemer Reviewed-by: Cuong Manh Le --- src/cmd/compile/internal/types2/typexpr.go | 16 +++++++++++++++- src/go/types/typexpr.go | 16 +++++++++++++++- src/internal/types/testdata/check/cycles5.go | 4 ++-- src/internal/types/testdata/check/cycles5a.go | 4 ++-- src/internal/types/testdata/check/decls1.go | 2 +- src/internal/types/testdata/check/issues0.go | 2 +- .../types/testdata/fixedbugs/issue39634.go | 8 ++++++-- .../types/testdata/fixedbugs/issue65344.go | 19 +++++++++++++++++++ 8 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 src/internal/types/testdata/fixedbugs/issue65344.go diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index 81adcbd9cfd010..d131306a142c69 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -48,6 +48,20 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *TypeName, wantType } check.recordUse(e, obj) + // If we want a type but don't have one, stop right here and avoid potential problems + // with missing underlying types. This also gives better error messages in some cases + // (see go.dev/issue/65344). + _, gotType := obj.(*TypeName) + if !gotType && wantType { + check.errorf(e, NotAType, "%s is not a type", obj.Name()) + // avoid "declared but not used" errors + // (don't use Checker.use - we don't want to evaluate too much) + if v, _ := obj.(*Var); v != nil && v.pkg == check.pkg /* see Checker.use1 */ { + v.used = true + } + return + } + // Type-check the object. // Only call Checker.objDecl if the object doesn't have a type yet // (in which case we must actually determine it) or the object is a @@ -57,7 +71,7 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *TypeName, wantType // informative "not a type/value" error that this function's caller // will issue (see go.dev/issue/25790). typ := obj.Type() - if _, gotType := obj.(*TypeName); typ == nil || gotType && wantType { + if typ == nil || gotType && wantType { check.objDecl(obj, def) typ = obj.Type() // type must have been assigned by Checker.objDecl } diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index c887b5115a2ab1..afb94b90261a49 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -49,6 +49,20 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *TypeName, wantType bo } check.recordUse(e, obj) + // If we want a type but don't have one, stop right here and avoid potential problems + // with missing underlying types. This also gives better error messages in some cases + // (see go.dev/issue/65344). + _, gotType := obj.(*TypeName) + if !gotType && wantType { + check.errorf(e, NotAType, "%s is not a type", obj.Name()) + // avoid "declared but not used" errors + // (don't use Checker.use - we don't want to evaluate too much) + if v, _ := obj.(*Var); v != nil && v.pkg == check.pkg /* see Checker.use1 */ { + v.used = true + } + return + } + // Type-check the object. // Only call Checker.objDecl if the object doesn't have a type yet // (in which case we must actually determine it) or the object is a @@ -58,7 +72,7 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *TypeName, wantType bo // informative "not a type/value" error that this function's caller // will issue (see go.dev/issue/25790). typ := obj.Type() - if _, gotType := obj.(*TypeName); typ == nil || gotType && wantType { + if typ == nil || gotType && wantType { check.objDecl(obj, def) typ = obj.Type() // type must have been assigned by Checker.objDecl } diff --git a/src/internal/types/testdata/check/cycles5.go b/src/internal/types/testdata/check/cycles5.go index a6145058bba9a2..de85c03d8a3d9f 100644 --- a/src/internal/types/testdata/check/cycles5.go +++ b/src/internal/types/testdata/check/cycles5.go @@ -161,8 +161,8 @@ var a12 = makeArray() func makeArray() (res T12) { return } // issue #20770 -var r /* ERROR "invalid cycle in declaration of r" */ = newReader() -func newReader() r +var r = newReader() +func newReader() r // ERROR "r is not a type" // variations of the theme of #8699 and #20770 var arr /* ERROR "cycle" */ = f() diff --git a/src/internal/types/testdata/check/cycles5a.go b/src/internal/types/testdata/check/cycles5a.go index ed5853e3f23932..e10f554e5c0120 100644 --- a/src/internal/types/testdata/check/cycles5a.go +++ b/src/internal/types/testdata/check/cycles5a.go @@ -161,8 +161,8 @@ var a12 = makeArray() func makeArray() (res T12) { return } // issue #20770 -var r /* ERROR "invalid cycle in declaration of r" */ = newReader() -func newReader() r +var r = newReader() +func newReader() r // ERROR "r is not a type" // variations of the theme of #8699 and #20770 var arr /* ERROR "cycle" */ = f() diff --git a/src/internal/types/testdata/check/decls1.go b/src/internal/types/testdata/check/decls1.go index 06f3b2e6cbf8fd..6cdbf27f4c2c18 100644 --- a/src/internal/types/testdata/check/decls1.go +++ b/src/internal/types/testdata/check/decls1.go @@ -63,7 +63,7 @@ var ( t12 complex64 = -(u + *t11) / *&v t13 int = a /* ERROR "shifted operand" */ << d t14 int = i << j - t15 math /* ERROR "not in selector" */ + t15 math /* ERROR "math is not a type" */ t16 math.xxx /* ERROR "undefined" */ t17 math /* ERROR "not a type" */ .Pi t18 float64 = math.Pi * 10.0 diff --git a/src/internal/types/testdata/check/issues0.go b/src/internal/types/testdata/check/issues0.go index dc6e0b0b223825..3bf4a3144656ed 100644 --- a/src/internal/types/testdata/check/issues0.go +++ b/src/internal/types/testdata/check/issues0.go @@ -104,7 +104,7 @@ func issue10979() { // issue11347 // These should not crash. -var a1, b1 /* ERROR "cycle" */ , c1 /* ERROR "cycle" */ b1 = 0 > 0<<""[""[c1]]>c1 +var a1, b1, c1 /* ERROR "cycle" */ b1 /* ERROR "b1 is not a type" */ = 0 > 0<<""[""[c1]]>c1 var a2, b2 /* ERROR "cycle" */ = 0 /* ERROR "assignment mismatch" */ /* ERROR "assignment mismatch" */ > 0<<""[b2] var a3, b3 /* ERROR "cycle" */ = int /* ERROR "assignment mismatch" */ /* ERROR "assignment mismatch" */ (1<<""[b3]) diff --git a/src/internal/types/testdata/fixedbugs/issue39634.go b/src/internal/types/testdata/fixedbugs/issue39634.go index 591b00e4046333..6fbc7cd7bc7298 100644 --- a/src/internal/types/testdata/fixedbugs/issue39634.go +++ b/src/internal/types/testdata/fixedbugs/issue39634.go @@ -2,9 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Examples adjusted to match new [T any] syntax for type parameters. +// Examples from the issue adjusted to match new [T any] syntax for type parameters. // Also, previously permitted empty type parameter lists and instantiations // are now syntax errors. +// +// The primary concern here is that these tests shouldn't crash the type checker. +// The quality of the error messages is secondary as these are all pretty esoteric +// or artificial test cases. package p @@ -39,7 +43,7 @@ type foo9[A any] interface { foo9 /* ERROR "invalid recursive type" */ [A] } func _() { var _ = new(foo9[int]) } // crash 12 -var u /* ERROR "cycle" */ , i [func /* ERROR "used as value" */ /* ERROR "used as value" */ (u, c /* ERROR "undefined" */ /* ERROR "undefined" */ ) {}(0, len /* ERROR "must be called" */ /* ERROR "must be called" */ )]c /* ERROR "undefined" */ /* ERROR "undefined" */ +var u, i [func /* ERROR "used as value" */ /* ERROR "used as value" */ (u /* ERROR "u is not a type" */ /* ERROR "u is not a type" */ , c /* ERROR "undefined" */ /* ERROR "undefined" */ ) {}(0, len /* ERROR "must be called" */ /* ERROR "must be called" */ )]c /* ERROR "undefined" */ /* ERROR "undefined" */ // crash 15 func y15() { var a /* ERROR "declared and not used" */ interface{ p() } = G15[string]{} } diff --git a/src/internal/types/testdata/fixedbugs/issue65344.go b/src/internal/types/testdata/fixedbugs/issue65344.go new file mode 100644 index 00000000000000..9f8337cf2b96fc --- /dev/null +++ b/src/internal/types/testdata/fixedbugs/issue65344.go @@ -0,0 +1,19 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type T1 C /* ERROR "C is not a type" */ + +// TODO(gri) try to avoid this follow-on error +const C = T1(0 /* ERROR "cannot convert 0 (untyped int constant) to type T1" */) + +type T2 V /* ERROR "V is not a type" */ + +var V T2 + +func _() { + // don't produce errors here + _ = C + V +}