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

Faulty logic in info op #86

Closed
yuhan0 opened this issue Apr 4, 2020 · 16 comments
Closed

Faulty logic in info op #86

yuhan0 opened this issue Apr 4, 2020 · 16 comments
Labels
bug Something isn't working

Comments

@yuhan0
Copy link
Contributor

yuhan0 commented Apr 4, 2020

Expected behavior

When calling orchard.info/info on a Java member or non-existent fully qualified symbol, the unqualified symbol should not be used to resolve a var in the current namespace.

(orchard.info/info 'user 'Integer/max)
(orchard.info/info 'user 'non-existing-ns/get)

should return the info for the Integer.max Java static member and nil respectively.

Actual behavior

Instead the unqualified symbols max and get are resolved to the clojure.core functions and produces an incorrect info response.

I traced it to this line in clj-meta:

(some-> ns (m/resolve-var unqualified-sym) (m/var-meta))

Even though sym is fully qualified, the processing step normalise-params added the key :unqualified-sym. I don't know enough to say if it's a predecence issue or if there should be an additional condition to not resolve unqualified-sym if the sym is fully qualified.

Steps to reproduce the problem

In Emacs, call cider-doc on the symbol Integer/max or observe the eldoc which displays the wrong arglists for clojure.core/max.

Environment & Version information

Clojure version

E.g. 1.10.2

Java version

E.g. 1.11

Operating system

macOS 10.15

@bbatsov bbatsov added the bug Something isn't working label Apr 5, 2020
@bbatsov
Copy link
Member

bbatsov commented Apr 5, 2020

I don't know enough to say if it's a predecence issue or if there should be an additional condition to not resolve unqualified-sym if the sym is fully qualified.

Sounds like we should have some additional check for qualified symbols. I don't remember the code details that much myself, but this should be easy to enough to fix. I guess there might also be an assumption that the caller should take care of the check, but it won't hurt to make the code in info more defensive.

Perhaps @jeffvalk will have something to add on this topic as well.

@arichiardi
Copy link
Contributor

I can have a look at this, probably a simple addition to the conditional logic there, thank you for the detailed report!

arichiardi added a commit to arichiardi/orchard that referenced this issue Apr 21, 2020
…huffle clj-meta

A treaty could be written on the intricacies of clj-meta. Previously,
java/resolve-symbol was not correctly consulted when resolving qualified
symbols. Moreover it was returning both static member information AND type
information.

The bug detected that this is not sufficient, cause we need to We treat it now
as a special case and we move it to the top. Unit tests were also added for
both issues in the ticket.
arichiardi added a commit to arichiardi/orchard that referenced this issue Apr 21, 2020
A treaty could be written on the intricacies of clj-meta. Previously,
java/resolve-symbol was at the end of the chain and was not consulted, cause
conflicts in unqualified names, like max, would result in earlier returns (for
instance of clojure.core/max).

The problem is deeper and moving java/resolve-symbol up would not solve all the
problems, as it is doing two things: returning static member information AND
type information. Basically it broke records and macro refer resolution.

This patch splits that function in two: java/resolve-symbol only checks if
there exist Java members, and java/resolve-type only takes care of full classes
and records.

Interleaving the two with (m/resolve-var unqualified-sym) magically fulfills
all the use cases. There be dragons.
@yuhan0
Copy link
Contributor Author

yuhan0 commented Jun 17, 2020

The case with Integer/max was solved, thanks! However the issue still remains with the other case where the symbol can't be resolved, like non-existing-ns/get.

@bbatsov
Copy link
Member

bbatsov commented Jun 17, 2020

Probably we'll have to do a deeper clean-up of that codebase at some point, as there's a lot of mess there. I might get to doing this in a month or so, but I can make no promises, as my backlog is already quite full. Any help is welcome!

@arichiardi
Copy link
Contributor

I would dare to disagree the code is a mess 😅

It's more Clojure's semantics non-linear - in any case of course any help is appreciated if I don't get to it soon.

I am quite confused though by the non-existent use case cause we test it and the test passed.

I will try to get there again

arichiardi added a commit to arichiardi/orchard that referenced this issue Jun 20, 2020
arichiardi added a commit to arichiardi/orchard that referenced this issue Jun 20, 2020
arichiardi added a commit to arichiardi/orchard that referenced this issue Jun 21, 2020
@arichiardi
Copy link
Contributor

arichiardi commented Jun 21, 2020

I think this one should be reopened.

This is the problem we have and it is one I am not sure how to solve.

The tension is between these two payloads (the first was part of #53):

{:ns orchard.test-ns, :sym replace, :dialect :clj, :unqualified-sym replace, :qualified-sym orchard.test-ns/replace}
{:ns orchard.test-ns, :sym Integer/max, :dialect :clj, :qualified-sym Integer/max, :unqualified-sym max, :computed-ns Integer}

The problem is that there exists both a clojure.string/replace and a java.lang.String/replace and java.lang is always available to the REPL. In order to resolve the clojure.string/replace referred in my orchard.test-ns I ns-resolve before resolving Java stuff.

This is all good, except that it means I resolve clojure.core/max before java.lang.Integer/max 😢

@bbatsov bbatsov reopened this Jun 21, 2020
@arichiardi
Copy link
Contributor

I think I will have to special-case for :refer clauses and make sure that:

  1. I resolve the :refer-ed symbols local to a namespace
  2. I resolve Java symbols
  3. I call resolve for anything else

@arichiardi
Copy link
Contributor

Nope, the problem is not with refer actually, it's about the symbol ambiguity. I will have to think about something else

@bbatsov
Copy link
Member

bbatsov commented Jun 23, 2020

@arichiardi We can do what we do with Java methods and return multiple candidates that the user can manually select, while defaulting the to the Clojure sym for eldoc.

@arichiardi
Copy link
Contributor

arichiardi commented Jun 23, 2020

@bbatsov Doesn't info always need to return one option? I think that if we change that it will be an even bigger reward. I have some idea - still haven't had time to implement it though.

@arichiardi
Copy link
Contributor

@yuhan0 I reallly really tried but I don't think I can produce a nil for (orchard.info/info 'user 'non-existing-ns/get).

In order to make pragmatic choices, I wonder if you can show me the piece of code (in cider) that presents the defect...I want to see if it is acceptable to display something like clojure.core/get in that case.

Thanks!

arichiardi added a commit to arichiardi/orchard that referenced this issue Jul 13, 2020
This patch unfixes clojure-emacs#86. It basically tries to restore a more linear flow in
clj-info and orchard.java, distinguishing a bit more between qualified and
unqualified patterns.
@yuhan0
Copy link
Contributor Author

yuhan0 commented Jul 13, 2020

The main entry point is cider-doc which displays a popup info buffer.
which then calls cider-doc -> cider-create-doc-buffer -> cider-var-info -> cider-sync-request:info
https://github.com/clojure-emacs/cider/blob/ed464423b5d3917384db460cff579adfd8d6d7fd/cider-client.el#L444

The other route is cider-eldoc-info which shows the var signature in the minibuffer.
This one forwards to cider-sync-request:eldoc which ends up calling the same orchard.info/info as parameter to the orchard.eldoc/eldoc function.
https://github.com/clojure-emacs/cider-nrepl/blob/94cc4be72ffc7cb868bd7acbf3ec0b44266f91f5/src/cider/nrepl/middleware/info.clj#L83

I wouldn't say it's unacceptable to display clojure.core/get in these cases, but it's definitely a "false positive" error that may cause confusion.

@yuhan0
Copy link
Contributor Author

yuhan0 commented Jul 13, 2020

Here's a contrived example:

(ns foo)
(defn get [x] "not clojure.core!")
(ns bar 
  (:require [foo])

;; via cider-uneval or some REPL command:
(ns-unmap 'foo 'get)

(foo/get :something) ;; <- cursor here, displays eldoc for clojure.core/get 

@yuhan0
Copy link
Contributor Author

yuhan0 commented Oct 8, 2021

Solved by #134 , thanks!

@yuhan0 yuhan0 closed this as completed Oct 8, 2021
@vemv
Copy link
Member

vemv commented Oct 8, 2021

Indeed! That PR comes to implement the unqualified symbol should not be used to resolve a var in the current namespace.

@arichiardi
Copy link
Contributor

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants