-
Notifications
You must be signed in to change notification settings - Fork 492
should omit type uint32 #61
Comments
Interesting. Hacking in some debugging statements I see that an underlying problem is |
Oh, that was reproduced on a Mac, which doesn't have IN_MOVED_TO. But it still occurs on a Linux machine too. |
I too was running golint on a Mac for a |
Is it just how the type checker handles constants? Certainly if I used the constants directly the compiler would be happy to consider them uint32. |
It still occurs with Aah, but on Linux the typechecker is deducing a type of "uint32" on the RHS. I suspect that it is doing the type deduction in full, more aggressively than golint was expecting. Hmmm. @adonovan, got any opinions here? I'm using info.TypeOf(v.Values[0]), where v is an *ast.ValueSpec, and finding that go/types is telling me it is a uint32. Is that expected? Is there a way to get the RHS's default type, rather than the type implied by the LHS of the var decl? |
Yeah, I wonder if we are supposed to notice that the RHS is a constant expression and treat that especially. I'm just a little surprised that info.TypeOf behaves this way. |
Simplified:
and likewise:
Given that they are typeless constants, I'm not too surprised. It does seem like some special handling may be needed to prevent this false positive. Thanks for looking into it. |
For each identifier that refers to a constant, the go/types API reports the effective type of the constant in that context, after convertUntyped() has changed it to the appropriate variable type and truncated the value if necessary. Only the *types.Const object itself holds the untruncated, "untyped", value. (I find the term "untyped" to be very confusing, especially when discussing var decls without an explicit type, such as var x = "foo".) I can see how this is not what you want here, but the logic in the typechecker is complex for a reason: the type of the LHS variable can be derived from the RHS constant, e.g. |
Thanks. So do you have a recommendation for what we should do here? |
adonovan explained the situation already. The type-checker determines the actual run-time type for constants once it needs them - in this case it determines that those constants must be uint32 (so it can verify that they actually fit). A compiler will also need this information (rather than the untyped value), so it makes sense. I think the lint warning is too aggressive: Even if repeating the type on the lhs is redundant, it may still make sense for a programmer to repeat it, for readability. You may want to target specifically more simple cases (var s string = "foo"; var i int = 42; etc.); basically cases where the lhs is constant, and the constants are literals or perhaps constant names declared in the same package. For more complex expressions like this one, or where the constants are declared elsewhere, it may make total sense to repeat the type in my mind. |
If this lint is kept, is there a way to determine that the RHS was an untyped constant? via *types.Const? If so then the LHS would only ever infer Maybe it's not worth holding on to this particular linter though. Hm. |
There's no way at the moment; the expression is given a type via the assignment and the prior type is not exposed - it's unfortunately one of the more complicated parts of the type checker. Perhaps it should - feel free to file an issue as a reminder (but I won't promise that it will be tackled anytime soon). |
I think I found a semi-ingenious workaround. Since I have the full AST, I can get the types.Scope for the variable declaration, use types.EvalNode to evaluate the RHS expression, and find the original type. It's a little cheeky, but it seems to work fine. |
Ah, yes! I was thinking about a solution along these lines (using types.New) but I forgot that we also have EvalNode, which is there exactly to evaluate arbitrary expressions in a given context (say for a debugger). It's not even cheeky; it's just a bit more work than one would hope to do because the original type for the rhs was determined once before (but than overridden because of the assignment). |
👍 Sounds perfect. Thanks David. |
This lets us more accurately suppress type omission suggestions, and also has the nice effect of throwing away some clumsy hacks. This helps address #61, but doesn't completely fix it.
This lets us more accurately suppress type omission suggestions, and also has the nice effect of throwing away some clumsy hacks. This helps address #61, but doesn't completely fix it.
39135ba partly addresses this, but it appears that types.EvalNode doesn't do cross-package name resolution (e.g. I get |
Is that a GOOS thing from #61 (comment)? It works here (Mac): ❯ golint
kqueue.go:414:17: should omit type uint32 from declaration of var newFlags; it will be inferred from the right-hand side
kqueue.go:466:17: should omit type uint32 from declaration of var newFlags; it will be inferred from the right-hand side
❯ go get -u github.com/golang/lint/golint
❯ golint Thanks. 😄 |
I thought it might have been, but then I tried net.IPv4len, and that's in |
Okay. And in case of a package selector error, does it decide not to report the lint? |
If the syscall package wasn't imported in the source it won't find it. EvalNode can only resolve names declared in the environment. But I'm not sure that's the problem.
|
Oh. Might this be why? 39135ba#diff-b2012451b01c3a63936f8be01c13c3e5R1238
So we need it outside of the context, but still with the same imports? |
Here's the full file I tested:
The typechecker doesn't complain at all during typechecking, so the |
Well, this is interesting. I am getting the scope from the So, it feels like |
Nope. This is of the hidden peculiarities of Go's scoping rules. Imported packages live in the file scope - because it's only visible in the Any other object in the package is declared in the package scope (because For correct scope, you will need the file scope. The type checker goes out The file scope can be found via the Info.Scopes map by using the correct
On Sun, Sep 14, 2014 at 9:11 PM, David Symonds notifications@github.com
|
I understand the scoping rules. I guess what I don't understand is why the Perhaps there needs to be a way to map from an ast.Expr to a *types.Scope, Thanks for looking at it. |
The scope of 'var x = ...' at the top-level has to be the package scope That is, when looking something up at the package-level, it always has to The type checker maintains the file scope info but then throws it away. I
On Sun, Sep 14, 2014 at 9:36 PM, David Symonds notifications@github.com
|
This is technically incorrect, as type inference assumes int.
This is similar to #7.
The line in question is this ugly bit of code:
Note: I updated to latest to confirm that this is still an issue, ae65d27.
The text was updated successfully, but these errors were encountered: