From 245e95dfabd77f337373bf2d6bb47cd353ad8d74 Mon Sep 17 00:00:00 2001 From: Robert Findley Date: Wed, 11 Jan 2023 14:41:03 -0500 Subject: go/types, types2: don't look up fields or methods when expecting a type As we have seen many times, the type checker must be careful to avoid accessing named type information before the type is fully set up. We need a more systematic solution to this problem, but for now avoid one case that causes a crash: checking a selector expression on an incomplete type when a type expression is expected. For golang/go#57522 Change-Id: I7ed31b859cca263276e3a0647d1f1b49670023a9 Reviewed-on: https://go-review.googlesource.com/c/go/+/461577 Run-TryBot: Robert Findley Auto-Submit: Robert Findley TryBot-Result: Gopher Robot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/types2/call.go | 21 ++++++++++++++++++++- src/cmd/compile/internal/types2/expr.go | 2 +- src/cmd/compile/internal/types2/typexpr.go | 2 +- 3 files changed, 22 insertions(+), 3 deletions(-) (limited to 'src/cmd') diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index 50343bf77a..7d660ca772 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -447,7 +447,7 @@ var cgoPrefixes = [...]string{ "_Cmacro_", // function to evaluate the expanded expression } -func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *Named) { +func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *Named, wantType bool) { // these must be declared before the "goto Error" statements var ( obj Object @@ -559,6 +559,25 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *Named) { goto Error } + // Avoid crashing when checking an invalid selector in a method declaration + // (i.e., where def is not set): + // + // type S[T any] struct{} + // type V = S[any] + // func (fs *S[T]) M(x V.M) {} + // + // All codepaths below return a non-type expression. If we get here while + // expecting a type expression, it is an error. + // + // See issue #57522 for more details. + // + // TODO(rfindley): We should do better by refusing to check selectors in all cases where + // x.typ is incomplete. + if wantType { + check.errorf(e.Sel, NotAType, "%s is not a type", syntax.Expr(e)) + goto Error + } + obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel) if obj == nil { // Don't report another error if the underlying type was invalid (issue #49541). diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index 9a0348e025..a3abbb9532 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -1587,7 +1587,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin return kind case *syntax.SelectorExpr: - check.selector(x, e, nil) + check.selector(x, e, nil, false) case *syntax.IndexExpr: if check.indexExpr(x, e) { diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index 4de658b0c4..0f3106d70a 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -256,7 +256,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) { case *syntax.SelectorExpr: var x operand - check.selector(&x, e, def) + check.selector(&x, e, def, true) switch x.mode { case typexpr: -- cgit v1.3