-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Add type restrictions to io #15698
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
base: master
Are you sure you want to change the base?
Add type restrictions to io #15698
Conversation
src/io.cr
Outdated
@@ -1146,7 +1146,7 @@ abstract class IO | |||
end | |||
|
|||
# Same as `pos`. | |||
def tell | |||
def tell : Int64 | Int32 |
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.
This look very odd to me. Especially as pos is noreturn. Where does this union type come from?
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.
I see Memory#pos return Int32 and Buffered#pos return Int64. The side effect being this wrapping def indirectly inherits the return types of those methods 🤷
Maybe better to omit the return type restriction in this case?
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.
Either that, or declare it to be typeof(pos), if that is possible 🤔
src/io/file_descriptor.cr
Outdated
def blocking=(value : Bool) : Int32? | ||
self.system_blocking = value | ||
end |
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.
These combination of input and return types should not be correct. The return type of an assignment should be the value assigned. Does system_blocking=
do anything weird?
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.
system_blocking=
may leak the return value of fcntl
.
We should probably return value
(c.f. #10083).
For this PR, I'd suggest to just set the return type restriction to Nil
.
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.
Per #10083, I could also update this method to return Bool
and put value
at the end?
Edit: Scratch that, I'll just do what you suggest in this case, and let that issue take care of this :)
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.
Yes, it's best to keep this PR focused on adding type restrictions, without changing anything else.
@@ -12,7 +12,7 @@ class IO | |||
EncodingOptions.check_invalid(invalid) | |||
end | |||
|
|||
def self.check_invalid(invalid) : Nil | |||
def self.check_invalid(invalid : Symbol?) : Nil |
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.
Thought (non-blocking): we should refactor to use an enum instead of a symbol. That would validate the value at comptime, instead of delaying to runtime, and it would be backward compatible, since symbols are automatically transformed into enums.
class IO
struct EncodingOptions
enum Invalid
Skip
end
getter name : String
getter invalid : Invalid?
def initialize(@name : String, @invalid : Invalid?)
end
end
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.
There are still a few details!
src/io/file_descriptor.cr
Outdated
self.system_close_on_exec = value | ||
end | ||
|
||
def self.fcntl(fd, cmd, arg = 0) | ||
Crystal::System::FileDescriptor.fcntl(fd, cmd, arg) | ||
end | ||
|
||
def fcntl(cmd, arg = 0) | ||
def fcntl(cmd : Int32, arg : Int32 = 0) : Int32 |
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.
Question: Why restrict the types to Int32
for the instance method, but not the class method above?
Also, the type should probably be Int
. There's no telling what the LibC definitions are using, and the Crystal::System methods are untyped anyway.
src/io/file_descriptor.cr
Outdated
@@ -267,7 +267,7 @@ class IO::FileDescriptor < IO | |||
system_tty? | |||
end | |||
|
|||
def reopen(other : IO::FileDescriptor) | |||
def reopen(other : IO::FileDescriptor) : File |
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.
Issue: The File
result type is wrong. We only happen to use File
in specs, but we return other
that is actually an IO::FileDescriptor
(or a descendant such as File
). Since type annotations don't coerce the value, the method will still return a File
or an IO::FileDescriptor
(verified).
def reopen(other : IO::FileDescriptor) : File | |
def reopen(other : IO::FileDescriptor) : IO::FileDescriptor |
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.
Dang, great catch!
src/io/encoding.cr
Outdated
@@ -146,7 +146,7 @@ class IO | |||
end | |||
end | |||
|
|||
def read_utf8(io, slice) : Int32 | |||
def read_utf8(io : IO, slice : Slice(UInt8)) : Int32 |
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.
Nitpick: maybe Bytes
?
def read_utf8(io : IO, slice : Slice(UInt8)) : Int32 | |
def read_utf8(io : IO, slice : Bytes) : Int32 |
This is the output of compiling cr-source-typer and running it with the below incantation:
This is related to #15682 .
I also reran the above command but without the
--union-size-threshold 2
, and updated several long union types toIO
by itself.