Skip to content

Commit 7d9bfb7

Browse files
committed
Formal specification of field types for abstract IO types
Most concrete IO types declare that a subset of their fields are other abstract IO types. As a result, if `obj1::IO`, and `obj2 = obj1.fieldwithabstracttype`, then inference has no way of knowing what type `obj2.status` returns. When `obj2.status` is used as an argument for `Base.somefunction`, this leaves such code vulnerable to invalidation via package specializations of `Base.somefunction` even when in practice there is no risk that any IO code will call the new package-supplied method. This provides a more formal interface for three non-exported abstract types: `LibuvStream`, `LibuvServer`, and `AbstractPipe`.
1 parent bf3ed57 commit 7d9bfb7

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed

base/io.jl

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,8 +333,27 @@ function open(f::Function, args...; kwargs...)
333333
end
334334
end
335335

336-
# Generic wrappers around other IO objects
336+
"""
337+
AbstractPipe
338+
339+
`AbstractPipe` is the abstract supertype for IO pipes that provide for communication between processes.
340+
341+
If `pipe isa AbstractPipe`, it must obey the following interface:
342+
343+
- `pipe.in` or `pipe.in_stream`, if present, must be of type `IO` and be used to provide input to the pipe
344+
- `pipe.out` or `pipe.out_stream`, if present, must be of type `IO` and be used for output from the pipe
345+
- `pipe.err` or `pipe.err_stream`, if present, must be of type `IO` and be used for writing errors from the pipe
346+
"""
337347
abstract type AbstractPipe <: IO end
348+
349+
function getproperty(pipe::AbstractPipe, name::Symbol)
350+
if name === :in || name === :in_stream || name === :out || name === :out_stream ||
351+
name === :err || name === :err_stream
352+
return getfield(pipe, name)::IO
353+
end
354+
return getfield(pipe, name)
355+
end
356+
338357
function pipe_reader end
339358
function pipe_writer end
340359

base/stream.jl

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,67 @@ end
1313

1414
## types ##
1515
abstract type IOServer end
16+
"""
17+
LibuvServer
18+
19+
An abstract type for IOServers handled by libuv.
20+
21+
If `server isa LibuvServer`, it must obey the following interface:
22+
23+
- `server.handle` must be a `Ptr{Cvoid}`
24+
- `server.status` must be an `Int`
25+
- `server.cond` must be a `GenericCondition`
26+
"""
1627
abstract type LibuvServer <: IOServer end
28+
29+
function getproperty(server::LibuvServer, name::Symbol)
30+
if name === :handle
31+
return getfield(server, :handle)::Ptr{Cvoid}
32+
elseif name === :status
33+
return getfield(server, :status)::Int
34+
elseif name === :cond
35+
return getfield(server, :cond)::GenericCondition
36+
else
37+
return getfield(server, name)
38+
end
39+
end
40+
41+
"""
42+
LibuvStream
43+
44+
An abstract type for IO streams handled by libuv.
45+
46+
If`stream isa LibuvStream`, it must obey the following interface:
47+
48+
- `stream.handle`, if present, must be a `Ptr{Cvoid}`
49+
- `stream.status`, if present, must be an `Int`
50+
- `stream.buffer`, if present, must be an `IOBuffer`
51+
- `stream.sendbuf`, if present, must be a `Union{Nothing,IOBuffer}`
52+
- `stream.cond`, if present, must be a `GenericCondition`
53+
- `stream.lock`, if present, must be an `AbstractLock`
54+
- `stream.throttle`, if present, must be an `Int`
55+
"""
1756
abstract type LibuvStream <: IO end
1857

58+
function getproperty(stream::LibuvStream, name::Symbol)
59+
if name === :handle
60+
return getfield(stream, :handle)::Ptr{Cvoid}
61+
elseif name === :status
62+
return getfield(stream, :status)::Int
63+
elseif name === :buffer
64+
return getfield(stream, :buffer)::IOBuffer
65+
elseif name === :sendbuf
66+
return getfield(stream, :sendbuf)::Union{Nothing,IOBuffer}
67+
elseif name === :cond
68+
return getfield(stream, :cond)::GenericCondition
69+
elseif name === :lock
70+
return getfield(stream, :lock)::AbstractLock
71+
elseif name === :throttle
72+
return getfield(stream, :throttle)::Int
73+
else
74+
return getfield(stream, name)
75+
end
76+
end
1977

2078
# IO
2179
# +- GenericIOBuffer{T<:AbstractArray{UInt8,1}} (not exported)

0 commit comments

Comments
 (0)