diff --git a/base/strings/unicode.jl b/base/strings/unicode.jl index a3b06063b98ac..cc02412925d14 100644 --- a/base/strings/unicode.jl +++ b/base/strings/unicode.jl @@ -5,7 +5,8 @@ module Unicode import Base: show, ==, hash, string, Symbol, isless, length, eltype, convert, isvalid, ismalformed, isoverlong, iterate, - AnnotatedString, AnnotatedChar, annotated_chartransform + AnnotatedString, AnnotatedChar, annotated_chartransform, + @assume_effects # whether codepoints are valid Unicode scalar values, i.e. 0-0xd7ff, 0xe000-0x10ffff @@ -385,7 +386,8 @@ julia> islowercase('❤') false ``` """ -islowercase(c::AbstractChar) = ismalformed(c) ? false : Bool(ccall(:utf8proc_islower, Cint, (UInt32,), UInt32(c))) +islowercase(c::AbstractChar) = ismalformed(c) ? false : + Bool(@assume_effects :foldable @ccall utf8proc_islower(UInt32(c)::UInt32)::Cint) # true for Unicode upper and mixed case @@ -409,7 +411,8 @@ julia> isuppercase('❤') false ``` """ -isuppercase(c::AbstractChar) = ismalformed(c) ? false : Bool(ccall(:utf8proc_isupper, Cint, (UInt32,), UInt32(c))) +isuppercase(c::AbstractChar) = ismalformed(c) ? false : + Bool(@assume_effects :foldable @ccall utf8proc_isupper(UInt32(c)::UInt32)::Cint) """ iscased(c::AbstractChar) -> Bool diff --git a/test/char.jl b/test/char.jl index 1d3579013ad18..5a522dfd1c743 100644 --- a/test/char.jl +++ b/test/char.jl @@ -360,3 +360,21 @@ end @test Base.IteratorSize(Char) == Base.HasShape{0}() @test convert(ASCIIChar, 1) == Char(1) end + +@testset "foldable isuppercase/islowercase" begin + v = @inferred (() -> Val(isuppercase('C')))() + @test v isa Val{true} + v = @inferred (() -> Val(islowercase('C')))() + @test v isa Val{false} + + struct MyChar <: AbstractChar + x :: Char + end + Base.codepoint(m::MyChar) = codepoint(m.x) + MyChar(x::UInt32) = MyChar(Char(x)) + + v = @inferred (() -> Val(isuppercase(MyChar('C'))))() + @test v isa Val{true} + v = @inferred (() -> Val(islowercase(MyChar('C'))))() + @test v isa Val{false} +end