Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

go/types: missing Info.Types for *ast.FuncType #70908

Closed
adonovan opened this issue Dec 18, 2024 · 9 comments
Closed

go/types: missing Info.Types for *ast.FuncType #70908

adonovan opened this issue Dec 18, 2024 · 9 comments
Assignees
Labels
Documentation Issues describing a change to documentation. NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@adonovan
Copy link
Member

In this program, types.Info.Types records no type for f's ast.FuncType node. I think it should:

package p

func f() (int, string) {
    return 0, "" 
}
Screenshot 2024-12-18 at 1 29 13 PM

@madelinekalil

@gabyhelp
Copy link

Related Issues

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

@Agent-Hellboy
Copy link

Agent-Hellboy commented Dec 23, 2024

Hi @adonovan,

I’d like to work on this if @madelinekalil approve the issue. I’ve recently added a PR on a mini parser for go.mod, and the Go codebase looks clean and approachable. I am particularly interested in the parser, AST, and type-checking stages, and I want to contribute to these areas as they seem beginner-friendly and a great way to start learning a language's type system through hands-on experience.

patch:

diff --git a/src/go/types/signature.go b/src/go/types/signature.go
index 681eb85fd7..590e0a982b 100644
--- a/src/go/types/signature.go
+++ b/src/go/types/signature.go
@@ -106,12 +106,18 @@ func (s *Signature) String() string   { return TypeString(s, nil) }
 
 // funcType type-checks a function or method type.
 func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) {
        check.openScope(ftyp, "function")
        check.scope.isFunc = true
        check.recordScope(ftyp, check.scope)
        sig.scope = check.scope
        defer check.closeScope()
 
+       if check.Info.Types != nil {
+               check.recordTypeAndValue(ftyp, typexpr, sig, nil)
+       }
+
        // collect method receiver, if any
        var recv *Var
        var rparams *TypeParamList

@dr2chase dr2chase added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Dec 23, 2024
@adonovan
Copy link
Member Author

I’d like to work on this if @madelinekalil approve the issue. I’ve recently added a PR on a mini parser for go.mod, and the Go codebase looks clean and approachable. I am particularly interested in the parser, AST, and type-checking stages

Thanks for your interest! @madelinekalil discovered the bug, but I think @griesemer is the best person to decide whether the simple fix you suggest is the right one. I know in the past there have been several discussions about when exactly the type checker guarantees to record a type for an expression, and it's possible this one lies in a grey area since, in context, the FuncType it isn't strictly a term or a type. Perhaps the most significant part of the fix will be to clarify the documentation on precisely what the user can safely assume.

they seem beginner-friendly

I have never heard go/types described that way before! ;-)

@Agent-Hellboy
Copy link

but I think @griesemer is the best person to decide whether the simple fix you suggest is the right one.

no problem. I can understand, I will keep looking at the issues and PRs and learning.

I have never heard go/types described that way before! ;-)

No no, I mean I am interested, and at least I can understand issues associated with these layers.

@griesemer griesemer added NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. and removed NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. labels Jan 6, 2025
@griesemer griesemer added this to the Backlog milestone Jan 6, 2025
@griesemer
Copy link
Contributor

I looked into this in fair detail:

For this program:

package p

var x int
var y = 1.0

func f() (int, string) {
    return 0, ""
}

var g func()

we get the following type recordings (playground):

Types
	 p:7:12 	 0 	 {4 int 0}
	 p:7:15 	 "" 	 {4 string ""}
	 p:3:7 	 int 	 {3 int <nil>}
	 p:4:9 	 1.0 	 {4 float64 1}
	 p:6:11 	 int 	 {3 int <nil>}
	 p:6:16 	 string 	 {3 string <nil>}
	 p:10:7 	 func() 	 {3 func() <nil>}
Defs
	 p:10:5 	 g 	 var p.g func()
	 p:1:9 	 p 	 <nil>
	 p:3:5 	 x 	 var p.x int
	 p:4:5 	 y 	 var p.y float64
	 p:6:6 	 f 	 func p.f() (int, string)

The type for f is recorded (via an Object) in the Info.Defs map since f is a declaration, so the type information is definitely present. For the variable x we record the type in Info.Defs (as expected), but we also have the type int recorded in the Info.Types map since we have a (syntactic) type expression int.

Presumably, the argument is that since we record the type for the type expression int we should do the same for the signature "expressions" in function declarations.

Yet, we don't do it for function declarations, because there's no obvious syntactic function type expression present in the source (e.g. we don't write f func() (int string)), we mix the function type into the declaration. The ast.FuncDecl in th AST is artificial in that sense.

Note that we definitely record the function type in info.Types when we have an explicit syntactic function type (line 10).

I am not convinced we should make the suggested change. For one it has been working like this for more than a decade and nobody complained. Second, I am concerned that recording this information may cause unexpected bugs (due to tools not expecting the data). Finally, for generic functions, go/ast records type parameters with the ast.FuncType, but the syntax package records type parameters with the FuncDecl node, so there's no obvious 1:1 correspondence between a FuncType node and the respective types.Signature in that sense, exactly because syntactically we actually don't have a clear-cut function type for function declarations.

As an aside, the suggested fix doesn't look right; that type information is recorded externally, and doing it in Checker.funcType may lead to repeated recordings.

All in all, I believe we should leave things as they are.
@adonovan, @findleyr Thoughts?

@adonovan
Copy link
Member Author

adonovan commented Jan 6, 2025

Yeah, I agree it's a grey area. I think a reasonable resolution would be to document more explicitly at Info.Types what the client can expect.

@gopherbot
Copy link
Contributor

Change https://go.dev/cl/640776 mentions this issue: go/types, types2: expand documentation for Info.Types map

@findleyr
Copy link
Member

findleyr commented Jan 7, 2025

It is probably simplest not to change this behavior, since this has been the case for a long time. Improving documentation sounds like a reasonable solution.

@gopherbot
Copy link
Contributor

Change https://go.dev/cl/640596 mentions this issue: go/types, types2: don't register interface methods in Info.Types map

@dmitshur dmitshur added Documentation Issues describing a change to documentation. NeedsFix The path to resolution is known, but the work has not been done. and removed NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. labels Jan 8, 2025
@dmitshur dmitshur modified the milestones: Backlog, Go1.24 Jan 8, 2025
wyf9661 pushed a commit to wyf9661/go that referenced this issue Jan 21, 2025
Function types for function (and method) declarations do not
appear in Info.Types maps, only Info.Defs maps, because the
function type is implicit in the declaration and not a proper
(function) type expression. This is true even though the AST
represents these types via an (artificial) FuncType node.

Document this explicitly in the API.

No functional code changes.

Fixes golang#70908.

Change-Id: I2aa897daed04e7ad0fa8b625d9adc7b423c57387
Reviewed-on: https://go-review.googlesource.com/c/go/+/640776
Reviewed-by: Alan Donovan <[email protected]>
Auto-Submit: Robert Griesemer <[email protected]>
Reviewed-by: Robert Griesemer <[email protected]>
Reviewed-by: Robert Findley <[email protected]>
LUCI-TryBot-Result: Go LUCI <[email protected]>
gopherbot pushed a commit that referenced this issue Feb 3, 2025
Methods declared in an interface have a signature and FuncType in the
AST, but they do not express a syntactic function type expression.
Treat them like ordinary function/method declarations and do not record
them in the Info.Types map. This removes an inconsistency in the way
function types are recorded.

Follow-up on CL 640776.

For #70908.

Change-Id: I60848f209b40b008039c014fb8b7b279361487b9
Reviewed-on: https://go-review.googlesource.com/c/go/+/640596
LUCI-TryBot-Result: Go LUCI <[email protected]>
Reviewed-by: Robert Griesemer <[email protected]>
Auto-Submit: Robert Griesemer <[email protected]>
Reviewed-by: Alan Donovan <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Documentation Issues describing a change to documentation. NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

No branches or pull requests

8 participants