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

Casts can have a side-effect and thus their object can be used #551

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

nobodywasishere
Copy link
Contributor

No description provided.

@Sija
Copy link
Member

Sija commented Jan 29, 2025

What does this change is meant to achieve, since as far as I understand this visitor class is meant to capture the return value of expression?

@nobodywasishere
Copy link
Contributor Author

There are methods such as this in the stdlib that use the fact that as raises if the cast cannot be performed. This means any value of the obj should be counted as being used. Without this change, the below with Lint/UnusedInstanceVariableAccess marks @raw as being unused (due to the Nil return type)

  # Checks that the underlying value is `Nil`, and returns `nil`.
  # Raises otherwise.
  def as_nil : Nil
    @raw.as(Nil)
  end

@Sija
Copy link
Member

Sija commented Jan 29, 2025

It seems to me there are some logic faults in here:

a) Any object that's being used in a Call should be counted as used
b) Last expression in methods with Nil return type restriction shouldn't be disregarded

@nobodywasishere
Copy link
Contributor Author

Any object that's being used in a Call should be counted as used

Casts aren't Calls, but fair enough. We know that (most) pseudo methods don't have side-effects, so I was fine with not counting their objects as used. This may not be necessary anymore once Lint/UnusedPseudoMethod is added, so I'll change that here for the rest of the pseudo methods.

Last expression in methods with Nil return type restriction shouldn't be disregarded

What's your reasoning for this? With this, I've found a handful of places in the stdlib where the return type was Nil but there was still an attempt to return a local variable's value. It can be useful to catch these cases. If it's about wanting semantic analysis in order to verify it's actually the stdlib Nil, fair enough and I can change that too.

@Sija
Copy link
Member

Sija commented Jan 29, 2025

What's your reasoning for this? With this, I've found a handful of places in the stdlib where the return type was Nil but there was still an attempt to return a local variable's value. It can be useful to catch these cases. If it's about wanting semantic analysis in order to verify it's actually the stdlib Nil, fair enough and I can change that too.

It's pretty common to simply leave the last expression in such methods as is - which is not a mistake, since the Nil return type restriction enforces the return value to nil, anyway.

Last line of def bodies are always considered used (regardless of return type restriction)
Copy link
Member

@Sija Sija left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not sure if the casts should increment the stack - i.e. what cases does that cover?

@nobodywasishere
Copy link
Contributor Author

Incrementing the stack before visiting the cast object tells the visitor that the object's return value is used by the cast. It means 1.as(Int32) won't flag the 1 as unused if it's in a void context.

@Sija
Copy link
Member

Sija commented Jan 29, 2025

Ok, I guess my confusion stems from the fact that it technically is still unused, yet as might have side-effects. What about as? though? It can't raise so it should still count as unused, doesn't it?

@nobodywasishere
Copy link
Contributor Author

Lint/UnusedPseudoMethods will handle marking as? and the like as unused (outside of this PR), but even if the as? is unused, it's object is still used by the as? itself. Otherwise we'll end up with things like this, which doesnt make sense (only the unused pseudo method should be reported imo):

"my string".as?(String)
# ^^^^^^^^^ error: Unused literal
          # ^^^^^^^^^^^ error: Unused pseudo method

This was my mistake when originally implementing the ImplicitReturnVisitor.

@Sija Sija requested a review from veelenga January 29, 2025 20:41
@Sija Sija added this to the 1.7.0 milestone Jan 29, 2025
@Sija Sija added the bug label Jan 29, 2025
@Sija
Copy link
Member

Sija commented Jan 30, 2025

It's pretty common to simply leave the last expression in such methods as is - which is not a mistake, since the Nil return type restriction enforces the return value to nil, anyway.

I probably should've had add that this is only relevant to the expressions with side-effects and not literals and such, sorry for the confusion.

@nobodywasishere
Copy link
Contributor Author

So if there's a literal or an unused variable access on the last line of a method with a Nil return type restriction, are you okay with flagging it as unused?

@Sija
Copy link
Member

Sija commented Jan 30, 2025

@nobodywasishere That's correct.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants