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

Object#const_defined? triggers a warning for deprecated constant #5002

Closed
janko opened this issue Jan 23, 2018 · 5 comments
Closed

Object#const_defined? triggers a warning for deprecated constant #5002

janko opened this issue Jan 23, 2018 · 5 comments
Milestone

Comments

@janko
Copy link

janko commented Jan 23, 2018

Environment

$ jruby -v
jruby 9.1.15.0 (2.3.3) 2017-12-07 929fde8 Java HotSpot(TM) 64-Bit Server VM 25.40-b25 on 1.8.0_40-b27 +jit [darwin-x86_64]
$ uname -a
Darwin Jankos-MacBook-Pro-2.local 17.3.0 Darwin Kernel Version 17.3.0: Thu Nov  9 18:09:22 PST 2017; root:xnu-4570.31.3~1/RELEASE_X86_64 x86_64

Expected Behavior

After deprecating a constant, asking whether that constant is defined doesn't trigger a deprecation warning on MRI:

Object.deprecate_constant(:Kernel)
Object.const_defined?(:Kernel)

Actual Behavior

On JRuby the Object#const_defined? call triggers a deprecation warning:

warning: constant ::Kernel is deprecated

I'm not saying this behaviour is bad, but it would probably be nice if the behaviour was the same as MRI when possible.

@janko janko changed the title Object#const_defined? shouldn't trigger warning for deprecated constant Object#const_defined? triggers a warning for deprecated constant Jan 23, 2018
@headius
Copy link
Member

headius commented Feb 13, 2018

Ok I'm really confused why MRI does not display this warning. As far as I can tell, the const_defined? code calls rb_const_get which calls rb_const_warn_if_deprecated, which always warns. I'm missing something.

@headius
Copy link
Member

headius commented Feb 13, 2018

Ok, I figured it out by step debugging. If const_defined? is called with a single symbol, it uses simpler logic (that does not check deprecation) for checking if that name is defined in the target module.

However we do not appear to have that simpler logic. RubyModule.isConstantDefined is similar but not quite.

@enebo
Copy link
Member

enebo commented Feb 13, 2018

I am generally in favor of matching MRI behavior but this really appears to be a bug in MRI. Why would "Kernel" as argument trigger it while :Kernel does not? I think we should WONTFIX this and perhaps ask @janko-m to raise this on ruby-lang as an issue.

@headius
Copy link
Member

headius commented Feb 13, 2018

@enebo Ahh you are correct, that does seem to be an odd behavioral difference. I'd say that all forms of const_defined? should warn or none of them should.

@janko-m I would suggest opening a bug with MRI to clarify this behavior. I did try to port the relevant logic, and although it eliminates the warning it does not pass existing specs (so I missed something).

If MRI decides that this is correct behavior we can proceed to use this patch as a starting point to getting this special case to work the same way.

diff --git a/core/src/main/java/org/jruby/RubyModule.java b/core/src/main/java/org/jruby/RubyModule.java
index 59ea1b9ece..81cda9728a 100644
--- a/core/src/main/java/org/jruby/RubyModule.java
+++ b/core/src/main/java/org/jruby/RubyModule.java
@@ -3245,6 +3245,10 @@ public class RubyModule extends RubyObject {
             throw runtime.newNameError("wrong constant name ", fullName);
         }
 
+        if (sep == -1 && symbol instanceof RubySymbol) {
+            return runtime.newBoolean(mod.rb_const_defined_0(runtime, name, false, true, false));
+        }
+
         IRubyObject obj;
         while ( ( sep = name.indexOf("::") ) != -1 ) {
             final String segment = name.substring(0, sep);
@@ -3265,6 +3269,39 @@ public class RubyModule extends RubyObject {
         return runtime.newBoolean(obj != null);
     }
 
+    private boolean
+    rb_const_defined_0(Ruby runtime, String id, boolean exclude, boolean recurse, boolean visibility)
+    {
+        RubyModule tmp;
+        boolean mod_retry = false;
+        ConstantEntry ce;
+
+        tmp = this;
+        retry: while (true) {
+            while (tmp != null) {
+                if ((ce = tmp.constantEntryFetch(id)) != null) {
+                    if (visibility && ce.hidden) {
+                        return false;
+                    }
+                    if (ce.value == UNDEF && //!check_autoload_required(tmp, id, 0) &&
+                            tmp.getAutoloadConstant(id, false) == null)
+                        return false;
+                    return false;
+                }
+                if (!recurse) break;
+                tmp = tmp.superClass;
+            }
+            if (!exclude && !mod_retry && this.metaClass == runtime.getModule()) {
+                mod_retry = true;
+                tmp = runtime.getObject();
+                continue retry;
+            }
+            break retry;
+        }
+        return false;
+    }
+
+
     /** rb_mod_const_get
      *
      */

@headius headius closed this as completed Feb 13, 2018
@headius headius added this to the Won't Fix milestone Feb 13, 2018
@janko
Copy link
Author

janko commented Feb 16, 2018

@headius Thanks for the explanation, I will take it to the MRI team.

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

No branches or pull requests

3 participants