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

Make Class and all metaclasses non-abstract #11190

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

HertzDevil
Copy link
Contributor

@HertzDevil HertzDevil commented Sep 9, 2021

Resolves #11132. Resolves #9959. The following code will now fail to compile:

abstract class A
end

class B < A
  def self.foo
  end
end

class C < A
  def self.foo
  end
end

x = B || C
x.foo # Error: undefined method 'foo' for A.class (compile-time type is A+.class)

This is because the value of x can also be A, so a definition for A.foo must be present. Currently, if x is indeed A, calling x.foo leads to undefined behaviour whenever multiple target defs are available, because virtual dispatch on x does not produce a branch for A.class.

Does not affect #3835, because .new is still implicitly available on all metaclasses (and .allocate on all class metaclasses). Also related to #5956.

Making Class non-abstract doesn't seem to have any significant consequences yet.

@HertzDevil HertzDevil added kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:lang:type-system topic:compiler:semantic labels Sep 9, 2021
@straight-shoota
Copy link
Member

I believe the example in the OP should be abstract class A, right? Without abstract, the code already does not compile (dito first spec).

@beta-ziliani
Copy link
Member

Looks good, but CI is failing and we don't have access to the logs anymore. I will close and open it again to re-run the checks (🤷 )

@beta-ziliani
Copy link
Member

The problem is in this spec, which now incorrectly fails saying that Foo.new expects no argument.

      abstract class Foo
      end

      class Bar < Foo
        def initialize(@x : Int32)
        end

        def x
          @x
        end
      end

      ptr = Pointer(Foo.class).malloc(1_u64)
      ptr.value = Bar
      bar = ptr.value.new(1)
      bar.x

@HertzDevil
Copy link
Contributor Author

There is also this on the Windows CI now:

In src\resolvers\resolver.cr:31:21 

 31 | "#{self.class.key}: #{source}" 
                    ^-- 
Error: undefined method 'key' for Shards::Resolver.class (compile-time type is Shards::Resolver+.class)

I believe both of these cases indeed should be rejected, but it looks like we have to guard this behind a flag now.

@asterite what do you think? Is there a way to make only .new work?

@asterite
Copy link
Member

I think here we should be a bit more relaxed. The code should compile, but if it ends up calling that method in the base abstract type then a runtime error is produced. Then reason is that it's unlikely that will actually happen.

@HertzDevil
Copy link
Contributor Author

This indeed couldn't happen via self.class, so a different approach is needed. Maybe we need an internal type for all subclasses of a metaclass but not the metaclass itself...

@HertzDevil HertzDevil marked this pull request as draft January 29, 2022 22:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:compiler:semantic topic:lang:type-system
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Class should not be abstract [RFC] Metaclasses of abstract types should not themselves be abstract
4 participants