-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Disallow typeof in type restrictions #5192
Disallow typeof in type restrictions #5192
Conversation
def self.foo(x : typeof(self)) | ||
x | ||
end | ||
it "errros if using typeof" do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"errors"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. Fixed with an amend and force push.
"can't use typeof in type restrictions" | ||
end | ||
|
||
it "errros if using typeof inside generic type" do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
I'm preliminarily for this PR, it seems like a sane change, but i've never used this construct so i'm not sure what the possible usecases in the wild are. |
It doesn't matter what the use cases are, nor there's a point discussing in favor of keeping this feature. It simply shouldn't work and will anyway stop working in the future once we don't lazily solve type restrictions. |
I agree with this totally because However this PR is not perfect. class Foo
def foo
1
end
def bar(&callback : typeof(self.foo) ->)
yield foo
end
end
Foo.new.bar do |x|
p x
end These line should be fixed: crystal/src/compiler/crystal/semantic/call.cr Line 711 in 1ac8880
crystal/src/compiler/crystal/semantic/call.cr Line 721 in 1ac8880
crystal/src/compiler/crystal/semantic/call.cr Line 733 in 1ac8880
|
@makenowjust 🦅 👀 !! Thanks! I fixed those too now. |
@asterite I'm not sure |
What do you mean? |
@asterite These lines may be replaced by simple crystal/src/compiler/crystal/semantic/type_lookup.cr Lines 356 to 374 in ea4187c
|
Mmm... I'm still not sure I understand. But you can try to send a different PR, or show me the diff you want. |
@asterite FWIW I don't mind the removal of Would it be possible to store the original position of the overloaded method and then put it in that order once the type is resolved? That way we don't need forward declarations and you don't get weird issues like in: #4897 Not sure how hard that would be for the compiler, but it would make using Crystal extra nice IMO :D |
This change makes Forward declarations? Is this C? Why can't there be a Sema visitor which checks that all types are reachable afterwards? |
To answer the questions, the main issue is macros. Macros can run at the same time methods are defined. So for example you can have: class Foo
def foo(x : Int32)
end
def foo(x : SomeType)
end
end
{% for method in Foo.methods %}
puts {{method.stringify}}
{% end %} The above prints:
Is that correct? Well, if we have: alias SomeType = Int32
class Foo
def foo(x : Int32)
end
def foo(x : SomeType)
end
end
{% for method in Foo.methods %}
puts {{method.stringify}}
{% end %} Then we get:
because the second method redefines the first one. Move the So the only solution to this is to solve types and method as quickly as possible, and that means solving types in method declarations because we need to know if a method redefines another one, or whether a method is "stronger" than another to put it before others for multiple dispatch. So this issue is not that simple. I personally don't think forward declarations are that hard to deal with. You just write: class Foo; end and that's it. The only issue is having to do that when I think the language is too complex, maybe without a good reason... |
Then the actual bug is that the compiler doesn't check for this error case once the |
What error case? |
class Foo
def foo(x : Int32)
end
def foo(x : SomeType)
end
end
alias SomeType = Int32 Should give an error akin to
|
Oh, I see. Well, if someone wants to implement that whole change, please send a PR :-) It should also take into account simple types vs. union types. |
Ping |
Fixes #2052
Fixes #5189
Type restrictions in methods are currently lazily evaluated. That means that this doesn't give an error right now:
It only gives an error when you try to invoke it.
Eventually we'd like type restrictions to be solved as soon as found, to avoid confusions like this: #4897 . In that example, because BigRational didn't exist when defining the method, it got in an incorrect order in the overload list.
Because methods are defined and solved before "main code" is analyzed (method calls, etc.),
typeof
can't be used in type restrictions, just like it can be used in type declarations for instance variables.Note that because we aren't yet solving restrictions as soon as found, the error you will get when using
typeof
here will only happen when you try to invoke the method, just like in the example above. Eventually this will be fixed too.