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

Offer “did you mean” for assignment ops #10262

Merged
merged 1 commit into from
Jan 31, 2023

Conversation

som-snytt
Copy link
Contributor

@som-snytt som-snytt commented Jan 11, 2023

Backport the latest Dotty research on recommending members of nearly identical spelling. (MONIS.)

Bumps the edit distance to consider, sorts the result, and presents up to 4 suggestions. Those that are not first-rank receive a qualifying, "or perhaps?" An ellipsis indicates when there are other candidates not presented to the user.

Avoid suggesting wait for priv or name (that is more of a Wordle move). The tweaked restriction is that the edit distance cannot exceed half the word length (for either user identifier or candidate), but if all the chars written by the user appear in the candidate string, then use it, since swaps and repetitions are common typos. For example, for acb suggest abc but not for ade. (Tempted to take ade because of the common prefix.)

Sample dotty:

scala> c.priv
-- [E008] Not Found Error: ---------------------------------------------------------------------------------------------
1 |c.priv
  |^^^^^^
  |value priv is not a member of C - did you mean c.wait?
1 error found

Avoid offering advice for setter, as in this dotty message:

1 |def v = c y_= 1
  |        ^^^^^
  |        value y_= is not a member of C - did you mean c.x_=?

but do advise on ++=.

It is slightly incongruous to suggest did you mean +++ or x_=? probably because the shared element is the suffix _= or just =. Maybe edit distance should be 1 for the shortest identifiers. More precisely, when comparing two setters, strip the suffix first. Then normal criterion says don't recommend x for y, which would be tedious.

Dotty offers only one suggestion:

scala> "xyz".lengt
-- [E008] Not Found Error: ---------------------------------------------------------------------------------------------
1 |"xyz".lengt
  |^^^^^^^^^^^
  |value lengt is not a member of String - did you mean ("xyz" : String).length?
1 error found

scala> "xyz".lgnet
-- [E008] Not Found Error: ---------------------------------------------------------------------------------------------
1 |"xyz".lgnet
  |^^^^^^^^^^^
  |value lgnet is not a member of String - did you mean ("xyz" : String).lines?
1 error found

now we exclude lines in the first case (edit distance compared to token length) but include length in the second (because it is a word scramble):

scala> "xyz".lengt
             ^
       error: value lengt is not a member of String
       did you mean length?

scala> "xyz".lgnet
             ^
       error: value lgnet is not a member of String
       did you mean lines? or perhaps length?

@scala-jenkins scala-jenkins added this to the 2.13.11 milestone Jan 11, 2023
@som-snytt som-snytt marked this pull request as ready for review January 12, 2023 01:40
@som-snytt som-snytt marked this pull request as draft January 12, 2023 17:08
@som-snytt som-snytt changed the title Offer did you mean for assignment ops Offer did you mean for assignment ops [ci: last-only] Jan 14, 2023
@som-snytt som-snytt force-pushed the tweak/not-member-help branch 3 times, most recently from fb6b4b4 to 911eccc Compare January 15, 2023 03:09
@som-snytt som-snytt marked this pull request as ready for review January 15, 2023 07:13
@lrytz lrytz requested a review from SethTisue January 16, 2023 09:30
@som-snytt som-snytt force-pushed the tweak/not-member-help branch from 4f9ba73 to 7ae8c6b Compare January 18, 2023 04:57
@SethTisue
Copy link
Member

LGTM but I'm wondering about 90c1fa8, what's that about?

@som-snytt
Copy link
Contributor Author

som-snytt commented Jan 21, 2023

@SethTisue https://discord.com/channels/632150470000902164/632628489719382036/1063609622113562724

I haven't tested javac on this score yet. I noticed scalac files 2> errs will announce 19 errors on stdout. It is more obvious for all error output to go to stderr.

But what about warnings? Do they also print to stderr? I hope so. Yes, same for warnings.

➜  snips scalac -Xlint warn-only.scala 2> errs
1 warning

I vaguely recall considering this question, perhaps before the reporters re-refactor, but I didn't go that far back to check. This represents my current thinking.

Dotty uses only stderr, and I opened a ticket to beg them to reconsider.

@som-snytt
Copy link
Contributor Author

som-snytt commented Jan 21, 2023

I had to think too hard about what javac might warn about.

➜  snips javac -Xlint JWarn.java 2> errs
➜  snips cat errs
JWarn.java:5: warning: [empty] empty statement after if
                        ;
                        ^
JWarn.java:6: warning: [deprecation] getId() in Thread has been deprecated
                System.out.println(Thread.currentThread().getId());
                                                         ^
2 warnings

BTW scalac could include both the lint name and the -Wconf category cat name in the message.

@SethTisue
Copy link
Member

Could 90c1fa8 go in a separate PR, or is there some necessary connection to the rest of the changes here?

@som-snytt
Copy link
Contributor Author

Yes, it could.

Copy link
Member

@SethTisue SethTisue left a comment

Choose a reason for hiding this comment

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

LGTM, but let's wait to merge until scala/scala-dev#827 has been addressed so we can get a go-ahead from Jenkins

@som-snytt som-snytt force-pushed the tweak/not-member-help branch from 6858d20 to e781990 Compare January 24, 2023 20:06
@som-snytt
Copy link
Contributor Author

Squashed using artisanal squashing techniques.

@som-snytt
Copy link
Contributor Author

Oh, I needed this today! Except...

➜  scala git:(tweak/not-member-help) ✗ scala
Welcome to Scala 2.13.10 (OpenJDK 64-Bit Server VM, Java 19).
Type in expressions for evaluation. Or try :help.

scala> import collection.immutable.LazyList
import collection.immutable.LazyList

scala> 42 :: LazyList.empty
          ^
       error: value :: is not a member of scala.collection.immutable.LazyList[A]
       did you mean ++: or :++?

scala>
:quit
➜  scala git:(tweak/not-member-help) ✗ skala
Welcome to Scala 2.13.11-20230124-195821-e781990 (OpenJDK 64-Bit Server VM, Java 19).
Type in expressions for evaluation. Or try :help.

scala> import collection.immutable.LazyList
import collection.immutable.LazyList

scala> 42 :: LazyList.empty
          ^
       error: value :: is not a member of scala.collection.immutable.LazyList[A]
       did you mean +:, /:, :+, or :\? or...?

oh man, let me filter out those deprecations.

did you mean +: or :+? or perhaps ++: or :++?

d'oh! of course it doesn't do conversions yet.

scala> 42 :: LazyList.empty
          ^
       error: value :: is not a member of scala.collection.immutable.LazyList[A]
       did you mean #::, +:, or :+? or perhaps #:::? or...?

The full list of alternatives to present in this case

ALTS[List((1,#::), (1,+:), (1,:+), (2,#:::), (2,++:), (2,:++))]

So the final wistful or...? is an intimation of the last two results, which happen to be the two low-quality results in 2.13.10.

@SethTisue
Copy link
Member

so did you want to wait to merge this until you add some of those improvements, or should we book the progress?

@som-snytt
Copy link
Contributor Author

I'll add the commit in just a second. I just excluded any2stringadd from the results...

@som-snytt som-snytt force-pushed the tweak/not-member-help branch from e781990 to bc77b62 Compare January 25, 2023 22:05
@som-snytt
Copy link
Contributor Author

That second commit was an exceptionally low-throughput slog. "Just give me all the available implicits" and "I just want to exclude the arrow of pairing." Hey, Cupid's arrow is also for pairing. This Valentine's, we should celebrate tuples instead of couples.

@som-snytt som-snytt force-pushed the tweak/not-member-help branch from bc77b62 to 538abc8 Compare January 26, 2023 00:16
@som-snytt
Copy link
Contributor Author

The run/analyzerPlugins.scala test showed extra calls because expressions such as i += 1 induce a failure (because int has no += member). The third commit adds DeferredTypeError to capture the mechanism and crank the handle only if the string message is requested. This may be safe for short-term deferral, in this case, as it decides whether the expression can be rewritten or just fail with the error message. It would not be appropriate for long-lived warnings which are buffered indefinitely.

Backport dotty behavior of ranking results.
Improve by offering a few alternatives,
with subtle wording to differentiate
first rank from the rest.

Allow shorter matches if it looks like
the typo is char swaps and repetitions.
@som-snytt som-snytt force-pushed the tweak/not-member-help branch from 538abc8 to bb82366 Compare January 29, 2023 16:36
@som-snytt som-snytt changed the title Offer did you mean for assignment ops [ci: last-only] Offer did you mean for assignment ops Jan 29, 2023
@som-snytt
Copy link
Contributor Author

@SethTisue I dropped the commit for "conversions help" until I review it further (for performance reasons). Rebased just the commit you approved.

@SethTisue SethTisue changed the title Offer did you mean for assignment ops Offer “did you mean” for assignment ops Jan 31, 2023
@SethTisue SethTisue merged commit 2686321 into scala:2.13.x Jan 31, 2023
@SethTisue
Copy link
Member

One small step for a man, one giant leap for the Oxford comma.

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

Successfully merging this pull request may close these issues.

3 participants