Skip to content

Commit

Permalink
remove fallback constructor from Core.Inference
Browse files Browse the repository at this point in the history
Instead, define explicit constructors for built-in integer types in boot.jl.
  • Loading branch information
JeffBezanson committed Sep 15, 2017
1 parent 08d2f70 commit a07e7df
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 70 deletions.
2 changes: 1 addition & 1 deletion base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ for (fname, felt) in ((:zeros, :zero), (:ones, :one))
$fname(a::AbstractArray, ::Type{T}, dims...) where {T} = fill!(similar(a, T, dims...), $felt(T))
$fname(a::AbstractArray, ::Type{T}=eltype(a)) where {T} = fill!(similar(a, T), $felt(T))

$fname(::Type{T}, dims::NTuple{N, Any}) where {T, N} = fill!(Array{T,N}(Dims(dims)), $felt(T))
$fname(::Type{T}, dims::NTuple{N, Any}) where {T, N} = fill!(Array{T,N}(convert(Dims, dims)::Dims), $felt(T))
$fname(dims::Tuple) = ($fname)(Float64, dims)
$fname(::Type{T}, dims...) where {T} = $fname(T, dims)
$fname(dims...) = $fname(dims)
Expand Down
176 changes: 176 additions & 0 deletions base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,10 @@ mutable struct ErrorException <: Exception
ErrorException(msg::AbstractString) = new(msg)
end

macro _inline_meta()
Expr(:meta, :inline)
end

macro _noinline_meta()
Expr(:meta, :noinline)
end
Expand Down Expand Up @@ -438,4 +442,176 @@ show(@nospecialize a) = show(STDOUT, a)
print(@nospecialize a...) = print(STDOUT, a...)
println(@nospecialize a...) = println(STDOUT, a...)

# constructors for built-in types

import .Intrinsics: eq_int, trunc_int, lshr_int, sub_int, shl_int, bitcast, sext_int, zext_int, and_int

throw_inexacterror(f::Symbol, T::Type, val) = (@_noinline_meta; throw(InexactError(f, T, val)))

function is_top_bit_set(x)
@_inline_meta
eq_int(trunc_int(Int8, lshr_int(x, sub_int(shl_int(sizeof(x), 3), 1))), trunc_int(Int8, 1))
end

function check_top_bit(x)
@_inline_meta
is_top_bit_set(x) && throw_inexacterror(:check_top_bit, typeof(x), x)
x
end

function checked_trunc_sint(::Type{To}, x::From) where {To,From}
@_inline_meta
y = trunc_int(To, x)
back = sext_int(From, y)
eq_int(x, back) || throw_inexacterror(:trunc, To, x)
y
end

function checked_trunc_uint(::Type{To}, x::From) where {To,From}
@_inline_meta
y = trunc_int(To, x)
back = zext_int(From, y)
eq_int(x, back) || throw_inexacterror(:trunc, To, x)
y
end

toInt8(x::Int8) = x
toInt8(x::Int16) = checked_trunc_sint(Int8, x)
toInt8(x::Int32) = checked_trunc_sint(Int8, x)
toInt8(x::Int64) = checked_trunc_sint(Int8, x)
toInt8(x::Int128) = checked_trunc_sint(Int8, x)
toInt8(x::UInt8) = bitcast(Int8, check_top_bit(x))
toInt8(x::UInt16) = checked_trunc_sint(Int8, check_top_bit(x))
toInt8(x::UInt32) = checked_trunc_sint(Int8, check_top_bit(x))
toInt8(x::UInt64) = checked_trunc_sint(Int8, check_top_bit(x))
toInt8(x::UInt128) = checked_trunc_sint(Int8, check_top_bit(x))
toInt8(x::Bool) = and_int(zext_int(Int8, x), Int8(1))
toInt16(x::Int8) = sext_int(Int16, x)
toInt16(x::Int16) = x
toInt16(x::Int32) = checked_trunc_sint(Int16, x)
toInt16(x::Int64) = checked_trunc_sint(Int16, x)
toInt16(x::Int128) = checked_trunc_sint(Int16, x)
toInt16(x::UInt8) = zext_int(Int16, x)
toInt16(x::UInt16) = bitcast(Int16, check_top_bit(x))
toInt16(x::UInt32) = checked_trunc_sint(Int16, check_top_bit(x))
toInt16(x::UInt64) = checked_trunc_sint(Int16, check_top_bit(x))
toInt16(x::UInt128) = checked_trunc_sint(Int16, check_top_bit(x))
toInt16(x::Bool) = and_int(zext_int(Int16, x), Int16(1))
toInt32(x::Int8) = sext_int(Int32, x)
toInt32(x::Int16) = sext_int(Int32, x)
toInt32(x::Int32) = x
toInt32(x::Int64) = checked_trunc_sint(Int32, x)
toInt32(x::Int128) = checked_trunc_sint(Int32, x)
toInt32(x::UInt8) = zext_int(Int32, x)
toInt32(x::UInt16) = zext_int(Int32, x)
toInt32(x::UInt32) = bitcast(Int32, check_top_bit(x))
toInt32(x::UInt64) = checked_trunc_sint(Int32, check_top_bit(x))
toInt32(x::UInt128) = checked_trunc_sint(Int32, check_top_bit(x))
toInt32(x::Bool) = and_int(zext_int(Int32, x), Int32(1))
toInt64(x::Int8) = sext_int(Int64, x)
toInt64(x::Int16) = sext_int(Int64, x)
toInt64(x::Int32) = sext_int(Int64, x)
toInt64(x::Int64) = x
toInt64(x::Int128) = checked_trunc_sint(Int64, x)
toInt64(x::UInt8) = zext_int(Int64, x)
toInt64(x::UInt16) = zext_int(Int64, x)
toInt64(x::UInt32) = zext_int(Int64, x)
toInt64(x::UInt64) = bitcast(Int64, check_top_bit(x))
toInt64(x::UInt128) = checked_trunc_sint(Int64, check_top_bit(x))
toInt64(x::Bool) = and_int(zext_int(Int64, x), Int64(1))
toInt128(x::Int8) = sext_int(Int128, x)
toInt128(x::Int16) = sext_int(Int128, x)
toInt128(x::Int32) = sext_int(Int128, x)
toInt128(x::Int64) = sext_int(Int128, x)
toInt128(x::Int128) = x
toInt128(x::UInt8) = zext_int(Int128, x)
toInt128(x::UInt16) = zext_int(Int128, x)
toInt128(x::UInt32) = zext_int(Int128, x)
toInt128(x::UInt64) = zext_int(Int128, x)
toInt128(x::UInt128) = bitcast(Int128, check_top_bit(x))
toInt128(x::Bool) = and_int(zext_int(Int128, x), Int128(1))
toUInt8(x::Int8) = bitcast(UInt8, check_top_bit(x))
toUInt8(x::Int16) = checked_trunc_uint(UInt8, x)
toUInt8(x::Int32) = checked_trunc_uint(UInt8, x)
toUInt8(x::Int64) = checked_trunc_uint(UInt8, x)
toUInt8(x::Int128) = checked_trunc_uint(UInt8, x)
toUInt8(x::UInt8) = x
toUInt8(x::UInt16) = checked_trunc_uint(UInt8, x)
toUInt8(x::UInt32) = checked_trunc_uint(UInt8, x)
toUInt8(x::UInt64) = checked_trunc_uint(UInt8, x)
toUInt8(x::UInt128) = checked_trunc_uint(UInt8, x)
toUInt8(x::Bool) = and_int(zext_int(UInt8, x), UInt8(1))
toUInt16(x::Int8) = sext_int(UInt16, check_top_bit(x))
toUInt16(x::Int16) = bitcast(UInt16, check_top_bit(x))
toUInt16(x::Int32) = checked_trunc_uint(UInt16, x)
toUInt16(x::Int64) = checked_trunc_uint(UInt16, x)
toUInt16(x::Int128) = checked_trunc_uint(UInt16, x)
toUInt16(x::UInt8) = zext_int(UInt16, x)
toUInt16(x::UInt16) = x
toUInt16(x::UInt32) = checked_trunc_uint(UInt16, x)
toUInt16(x::UInt64) = checked_trunc_uint(UInt16, x)
toUInt16(x::UInt128) = checked_trunc_uint(UInt16, x)
toUInt16(x::Bool) = and_int(zext_int(UInt16, x), UInt16(1))
toUInt32(x::Int8) = sext_int(UInt32, check_top_bit(x))
toUInt32(x::Int16) = sext_int(UInt32, check_top_bit(x))
toUInt32(x::Int32) = bitcast(UInt32, check_top_bit(x))
toUInt32(x::Int64) = checked_trunc_uint(UInt32, x)
toUInt32(x::Int128) = checked_trunc_uint(UInt32, x)
toUInt32(x::UInt8) = zext_int(UInt32, x)
toUInt32(x::UInt16) = zext_int(UInt32, x)
toUInt32(x::UInt32) = x
toUInt32(x::UInt64) = checked_trunc_uint(UInt32, x)
toUInt32(x::UInt128) = checked_trunc_uint(UInt32, x)
toUInt32(x::Bool) = and_int(zext_int(UInt32, x), UInt32(1))
toUInt64(x::Int8) = sext_int(UInt64, check_top_bit(x))
toUInt64(x::Int16) = sext_int(UInt64, check_top_bit(x))
toUInt64(x::Int32) = sext_int(UInt64, check_top_bit(x))
toUInt64(x::Int64) = bitcast(UInt64, check_top_bit(x))
toUInt64(x::Int128) = checked_trunc_uint(UInt64, x)
toUInt64(x::UInt8) = zext_int(UInt64, x)
toUInt64(x::UInt16) = zext_int(UInt64, x)
toUInt64(x::UInt32) = zext_int(UInt64, x)
toUInt64(x::UInt64) = x
toUInt64(x::UInt128) = checked_trunc_uint(UInt64, x)
toUInt64(x::Bool) = and_int(zext_int(UInt64, x), UInt64(1))
toUInt128(x::Int8) = sext_int(UInt128, check_top_bit(x))
toUInt128(x::Int16) = sext_int(UInt128, check_top_bit(x))
toUInt128(x::Int32) = sext_int(UInt128, check_top_bit(x))
toUInt128(x::Int64) = sext_int(UInt128, check_top_bit(x))
toUInt128(x::Int128) = bitcast(UInt128, check_top_bit(x))
toUInt128(x::UInt8) = zext_int(UInt128, x)
toUInt128(x::UInt16) = zext_int(UInt128, x)
toUInt128(x::UInt32) = zext_int(UInt128, x)
toUInt128(x::UInt64) = zext_int(UInt128, x)
toUInt128(x::UInt128) = x
toUInt128(x::Bool) = and_int(zext_int(UInt128, x), UInt128(1))

# TODO: this is here to work around the 4 method limit in inference (#23210).
const BuiltinInts = Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8, Bool}
Int8(x::BuiltinInts) = toInt8(x)::Int8
Int16(x::BuiltinInts) = toInt16(x)::Int16
Int32(x::BuiltinInts) = toInt32(x)::Int32
Int64(x::BuiltinInts) = toInt64(x)::Int64
Int128(x::BuiltinInts) = toInt128(x)::Int128
UInt8(x::BuiltinInts) = toUInt8(x)::UInt8
UInt16(x::BuiltinInts) = toUInt16(x)::UInt16
UInt32(x::BuiltinInts) = toUInt32(x)::UInt32
UInt64(x::BuiltinInts) = toUInt64(x)::UInt64
UInt128(x::BuiltinInts) = toUInt128(x)::UInt128

UInt32(x::Char) = bitcast(UInt32, x)
Char(x::UInt32) = bitcast(Char, x)
Char(x::Number) = Char(UInt32(x))
(::Type{T})(x::Char) where {T<:Number} = T(UInt32(x))

(::Type{T})(x::T) where {T<:Number} = x

Int(x::Ptr) = bitcast(Int, x)
UInt(x::Ptr) = bitcast(UInt, x)
if Int === Int32
Int64(x::Ptr) = Int64(UInt32(x))
UInt64(x::Ptr) = UInt64(UInt32(x))
end
Ptr{T}(x::Union{Int,UInt,Ptr}) where {T} = bitcast(Ptr{T}, x)

ccall(:jl_set_istopmod, Void, (Any, Bool), Core, true)
6 changes: 2 additions & 4 deletions base/char.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

convert(::Type{Char}, x::UInt32) = reinterpret(Char, x)
convert(::Type{Char}, x::Number) = Char(UInt32(x))
convert(::Type{UInt32}, x::Char) = reinterpret(UInt32, x)
convert(::Type{T}, x::Char) where {T<:Number} = convert(T, UInt32(x))
convert(::Type{Char}, x::Number) = Char(x)
convert(::Type{T}, x::Char) where {T<:Number} = T(x)

rem(x::Char, ::Type{T}) where {T<:Number} = rem(UInt32(x), T)

Expand Down
3 changes: 0 additions & 3 deletions base/coreimg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@ eval(m, x) = Core.eval(m, x)
include(x) = Core.include(Inference, x)
include(mod, x) = Core.include(mod, x)

# conditional to allow redefining Core.Inference after base exists
isdefined(Main, :Base) || ((::Type{T})(arg) where {T} = convert(T, arg)::T)

function return_type end

## Load essential files and libraries
Expand Down
60 changes: 2 additions & 58 deletions base/int.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ const BitUnsigned64T = Union{Type{UInt8}, Type{UInt16}, Type{UInt32}, Type{UIn

const BitIntegerType = Union{map(T->Type{T}, BitInteger_types)...}

throw_inexacterror(f::Symbol, ::Type{T}, val) where T =
(@_noinline_meta; throw(InexactError(f, T, val)))
# calls constructors defined in boot.jl
convert(T::BitIntegerType, x::Union{BitInteger, Bool}) = T(x)

## integer comparisons ##

Expand Down Expand Up @@ -419,75 +419,19 @@ trailing_ones(x::Integer) = trailing_zeros(~x)
>>>(x::BitInteger, y::Int) =
select_value(0 <= y, x >>> unsigned(y), x << unsigned(-y))

function is_top_bit_set(x::BitInteger)
@_inline_meta
lshr_int(x, (sizeof(x) << 0x03) - 1) == rem(0x01, typeof(x))
end
function check_top_bit(x::BitInteger)
@_inline_meta
is_top_bit_set(x) && throw_inexacterror(:check_top_bit, typeof(x), x)
x
end

## integer conversions ##

function checked_trunc_sint(::Type{To}, x::From) where {To,From}
@_inline_meta
y = trunc_int(To, x)
back = sext_int(From, y)
x == back || throw_inexacterror(:trunc, To, x)
y
end

function checked_trunc_uint(::Type{To}, x::From) where {To,From}
@_inline_meta
y = trunc_int(To, x)
back = zext_int(From, y)
x == back || throw_inexacterror(:trunc, To, x)
y
end

for to in BitInteger_types, from in (BitInteger_types..., Bool)
if !(to === from)
if to.size < from.size
if to <: Signed
if from <: Unsigned
@eval convert(::Type{$to}, x::($from)) =
checked_trunc_sint($to, check_top_bit(x))
else
@eval convert(::Type{$to}, x::($from)) =
checked_trunc_sint($to, x)
end
else
@eval convert(::Type{$to}, x::($from)) =
checked_trunc_uint($to, x)
end
@eval rem(x::($from), ::Type{$to}) = trunc_int($to, x)
elseif from === Bool
# Bools use i8 storage and may have garbage in their 7 high bits
@eval convert(::Type{$to}, x::($from)) = zext_int($to, x) & $to(1)
@eval rem(x::($from), ::Type{$to}) = convert($to, x)
elseif from.size < to.size
if from <: Signed
if to <: Unsigned
@eval convert(::Type{$to}, x::($from)) =
sext_int($to, check_top_bit(x))
else
@eval convert(::Type{$to}, x::($from)) =
sext_int($to, x)
end
@eval rem(x::($from), ::Type{$to}) = sext_int($to, x)
else
@eval convert(::Type{$to}, x::($from)) = zext_int($to, x)
@eval rem(x::($from), ::Type{$to}) = convert($to, x)
end
else
if !((from <: Signed) === (to <: Signed))
# raise InexactError if x's top bit is set
@eval convert(::Type{$to}, x::($from)) = bitcast($to, check_top_bit(x))
else
@eval convert(::Type{$to}, x::($from)) = bitcast($to, x)
end
@eval rem(x::($from), ::Type{$to}) = bitcast($to, x)
end
end
Expand Down
6 changes: 2 additions & 4 deletions base/pointer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,10 @@ const C_NULL = bitcast(Ptr{Void}, 0)
# TODO: deprecate these conversions. C doesn't even allow them.

# pointer to integer
convert(::Type{T}, x::Ptr) where {T<:Union{Int,UInt}} = bitcast(T, x)
convert(::Type{T}, x::Ptr) where {T<:Integer} = convert(T, convert(UInt, x))
convert(::Type{T}, x::Ptr) where {T<:Integer} = T(UInt(x))

# integer to pointer
convert(::Type{Ptr{T}}, x::UInt) where {T} = bitcast(Ptr{T}, x)
convert(::Type{Ptr{T}}, x::Int) where {T} = bitcast(Ptr{T}, x)
convert(::Type{Ptr{T}}, x::Union{Int,UInt}) where {T} = Ptr{T}(x)

# pointer to pointer
convert(::Type{Ptr{T}}, p::Ptr{T}) where {T} = p
Expand Down
2 changes: 2 additions & 0 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,8 @@ static void flatten_type_union(jl_value_t **types, size_t n, jl_value_t **out, s

STATIC_INLINE const char *datatype_module_name(jl_value_t *t)
{
if (((jl_datatype_t*)t)->name->module == NULL)
return NULL;
return jl_symbol_name(((jl_datatype_t*)t)->name->module->name);
}

Expand Down

0 comments on commit a07e7df

Please sign in to comment.