From 3aec1972e58f45806ea0cfed3d825b1f2df9d4d5 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Tue, 20 Jun 2017 18:23:04 -0400 Subject: [PATCH 1/2] deprecate * in favor of new ++ concatenation operator (closes #11030) --- base/abstractarray.jl | 13 +++++++++ base/abstractarraymath.jl | 2 +- base/atomics.jl | 2 +- base/broadcast.jl | 2 +- base/client.jl | 2 +- base/dates/periods.jl | 4 +-- base/deprecated.jl | 16 ++++++----- base/distributed/cluster.jl | 2 +- base/exports.jl | 1 + base/interactiveutil.jl | 8 +++--- base/libgit2/callbacks.jl | 4 +-- base/libgit2/utils.jl | 2 +- base/libuv.jl | 2 +- base/linalg/cholesky.jl | 4 +-- base/linalg/generic.jl | 2 +- base/linalg/triangular.jl | 12 ++++----- base/loading.jl | 6 ++--- base/markdown/Common/block.jl | 2 +- base/markdown/GitHub/table.jl | 8 +++--- base/markdown/render/latex.jl | 2 +- base/markdown/render/plain.jl | 4 +-- base/markdown/render/rst.jl | 2 +- base/markdown/render/terminal/formatting.jl | 6 ++--- base/markdown/render/terminal/render.jl | 30 ++++++++++----------- base/meta.jl | 8 +++--- base/methodshow.jl | 10 +++---- base/path.jl | 14 +++++----- base/pkg/entry.jl | 16 +++++------ base/pkg/read.jl | 2 +- base/pkg/resolve.jl | 4 +-- base/printf.jl | 2 +- base/process.jl | 10 +++---- base/profile.jl | 2 +- base/promotion.jl | 23 ++++++++++++++++ base/reflection.jl | 2 +- base/repl/LineEdit.jl | 10 +++---- base/repl/REPLCompletions.jl | 6 ++--- base/repl/emoji_symbols.jl | 2 +- base/sharedarray.jl | 6 ++--- base/show.jl | 6 ++--- base/sparse/cholmod.jl | 24 ++++++++--------- base/sparse/sparsevector.jl | 2 +- base/sparse/umfpack.jl | 2 +- base/strings/basic.jl | 18 +++---------- base/strings/types.jl | 21 +++++++-------- base/strings/util.jl | 8 +++--- base/test.jl | 2 +- base/version.jl | 8 +++--- contrib/julia-config.jl | 4 +-- doc/src/manual/strings.md | 23 ++++------------ examples/typetree.jl | 2 +- src/julia-parser.scm | 16 ++++++----- test/channels.jl | 2 +- test/choosetests.jl | 2 +- test/dates/io.jl | 10 +++---- test/dates/periods.jl | 2 +- test/distributed_exec.jl | 4 +-- test/libgit2.jl | 10 +++---- test/numbers.jl | 18 ++++++------- test/pkg.jl | 4 +-- test/replcompletions.jl | 6 ++--- test/runtests.jl | 2 +- test/show.jl | 4 +-- test/socket.jl | 5 ++-- test/strings/basic.jl | 10 +++---- test/strings/types.jl | 2 +- test/unicode/utf8proc.jl | 4 +-- 67 files changed, 243 insertions(+), 233 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index fbd2ff7547b8f..1e3ffb7c7bca0 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -1299,6 +1299,19 @@ julia> hcat(c...) """ hcat(X...) = cat(Val{2}, X...) +""" + ++(X...) + +`++` is a generic concatenation operator. By default, it +calls [`vcat`](@ref), concatenating arrays and elements thereof. +For strings and characters, it performs string concatenation. +Similarly, for other types it may perform an appropriate concatenation +operation. +""" +++(X...) = concat(concat_typeof(X...), X...) +concat(::Type{<:Any}, X...) = vcat(X...) # default +concat_rule(::Type{<:AbstractArray}, S) = (@_inline_meta; Array) # arrays should concatenate to arrays + typed_vcat(T::Type, X...) = cat_t(Val{1}, T, X...) typed_hcat(T::Type, X...) = cat_t(Val{2}, T, X...) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 058170e3d5041..54555cb1bf97c 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -387,7 +387,7 @@ _rshps(shp, shp_i, sz, ::Tuple{}, o) = (n = length(shp); N = n + length(sz); _reperr("inner", n, N)) _rshps(shp, shp_i, sz, i, ::Tuple{}) = (n = length(shp); N = n + length(sz); _reperr("outer", n, N)) -_reperr(s, n, N) = throw(ArgumentError("number of " * s * " repetitions " * +_reperr(s, n, N) = throw(ArgumentError("number of " ++ s ++ " repetitions " ++ "($n) cannot be less than number of dimensions of input ($N)")) @propagate_inbounds function _repeat(A::AbstractArray, inner, outer) diff --git a/base/atomics.jl b/base/atomics.jl index f44edbeb75527..900c45ba2adef 100644 --- a/base/atomics.jl +++ b/base/atomics.jl @@ -421,7 +421,7 @@ for typ in atomictypes fn = Symbol("atomic_", rmw, "!") if (rmw == "max" || rmw == "min") && typ <: Unsigned # LLVM distinguishes signedness in the operation, not the integer type. - rmw = "u" * rmw + rmw = "u" ++ rmw end if typ <: Integer @eval $fn(x::Atomic{$typ}, v::$typ) = diff --git a/base/broadcast.jl b/base/broadcast.jl index b4fd9126727c4..90d57c497fa02 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -420,7 +420,7 @@ julia> string.(("one","two","three","four"), ": ", 1:4) "three: 3" "four: 4" -julia> Nullable("X") .* "Y" +julia> Nullable("X") .++ "Y" Nullable{String}("XY") julia> broadcast(/, 1.0, Nullable(2.0)) diff --git a/base/client.jl b/base/client.jl index 4013fcd42ceb1..016dd9ea918ef 100644 --- a/base/client.jl +++ b/base/client.jl @@ -219,7 +219,7 @@ parse_input_line(s::AbstractString) = parse_input_line(String(s)) function parse_input_line(io::IO) s = "" while !eof(io) - s *= readline(io, chomp=false) + s = s ++ readline(io, chomp=false) e = parse_input_line(s) if !(isa(e,Expr) && e.head === :incomplete) return e diff --git a/base/dates/periods.jl b/base/dates/periods.jl index 628e077b1aec8..817ededa8fc64 100644 --- a/base/dates/periods.jl +++ b/base/dates/periods.jl @@ -10,7 +10,7 @@ for period in (:Year, :Month, :Week, :Day, :Hour, :Minute, :Second, :Millisecond period_str = string(period) accessor_str = lowercase(period_str) # Convenience method for show() - @eval _units(x::$period) = " " * $accessor_str * (abs(value(x)) == 1 ? "" : "s") + @eval _units(x::$period) = " " ++ $accessor_str ++ (abs(value(x)) == 1 ? "" : "s") # periodisless @eval periodisless(x::$period, y::$period) = value(x) < value(y) # AbstractString parsing (mainly for IO code) @@ -334,7 +334,7 @@ function Base.string(x::CompoundPeriod) else s = "" for p in x.periods - s *= ", " * string(p) + s *= ", " ++ string(p) end return s[3:end] end diff --git a/base/deprecated.jl b/base/deprecated.jl index c47894dce94f4..731b5660b97a1 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -395,8 +395,8 @@ export $ # promote_op method where the operator is also a type function promote_op(op::Type, Ts::Type...) - depwarn("promote_op(op::Type, ::Type...) is deprecated as it is no " * - "longer needed in Base. If you need its functionality, consider " * + depwarn("promote_op(op::Type, ::Type...) is deprecated as it is no " ++ + "longer needed in Base. If you need its functionality, consider " ++ "defining it locally.", :promote_op) if isdefined(Core, :Inference) return Core.Inference.return_type(op, Tuple{Ts...}) @@ -721,8 +721,8 @@ _promote_array_type(::typeof(\), ::Type{<:Integer}, ::Type{Bool}, T::Type) = T _promote_array_type(F, ::Type{<:Integer}, ::Type{Bool}, T::Type) = T _promote_array_type{T<:AbstractFloat}(F, ::Type{<:Union{Complex, Real}}, ::Type{Complex{T}}, ::Type) = Complex{T} function promote_array_type(F, R, S, T) - Base.depwarn("`promote_array_type` is deprecated as it is no longer needed " * - "in Base. See https://github.com/JuliaLang/julia/issues/19669 " * + Base.depwarn("`promote_array_type` is deprecated as it is no longer needed " ++ + "in Base. See https://github.com/JuliaLang/julia/issues/19669 " ++ "for more information.", :promote_array_type) _promote_array_type(F, R, S, T) end @@ -1165,8 +1165,8 @@ end return func else msg = "$f($sig; negate=$negate) is deprecated, use $f(" - negate && (msg *= "!") - msg *= "$sig) instead." + negate && (msg = msg ++ "!") + msg = msg ++ "$sig) instead." Base.depwarn(msg, f) return negate ? !func : func end @@ -1434,6 +1434,10 @@ module Operators end export Operators +# deprecate old string-concatenation ops in favor of ++ +@deprecate (*)(s1::AbstractString, ss::AbstractString...) (++)(s1, ss...) +@deprecate (^)(s::AbstractString, r::Integer) repeat(s,r) + # PR #21956 # This mimics the structure as it was defined in Base to avoid directly breaking code # that assumes this structure diff --git a/base/distributed/cluster.jl b/base/distributed/cluster.jl index 3fdb113989573..502ca9c321e4c 100644 --- a/base/distributed/cluster.jl +++ b/base/distributed/cluster.jl @@ -112,7 +112,7 @@ function check_worker_state(w::Worker) wait(w.c_state) w.state == W_CREATED && error("peer $(w.id) didn't connect to $(myid()) within $timeout seconds") else - error("peer $(w.id) is not connected to $(myid()). Topology : " * string(PGRP.topology)) + error("peer $(w.id) is not connected to $(myid()). Topology : ", PGRP.topology) end end end diff --git a/base/exports.jl b/base/exports.jl index 34e266a0ee002..1584d58d77c6b 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -236,6 +236,7 @@ export :, =>, ∘, + ++, A_ldiv_B!, A_ldiv_Bc, A_ldiv_Bt, diff --git a/base/interactiveutil.jl b/base/interactiveutil.jl index 32cfb81047023..7ec501fd97296 100644 --- a/base/interactiveutil.jl +++ b/base/interactiveutil.jl @@ -222,7 +222,7 @@ function _show_cpuinfo(io::IO, info::Sys.CPUinfo, header::Bool=true, prefix::Abs tck = Sys.SC_CLK_TCK if header println(io, info.model, ": ") - print(io, " "^length(prefix)) + print(io, repeat(" ",length(prefix))) if tck > 0 @printf(io, " %5s %9s %9s %9s %9s %9s\n", "speed", "user", "nice", "sys", "idle", "irq") @@ -419,8 +419,8 @@ function gen_call_with_extracted_types(__module__, fcn, ex0) end if (!is_macro && ex.head == :thunk) || exret.head == :none exret = Expr(:call, :error, "expression is not a function call, " - * "or is too complex for @$fcn to analyze; " - * "break it down to simpler parts if possible") + ++ "or is too complex for @$fcn to analyze; " + ++ "break it down to simpler parts if possible") end exret end @@ -690,7 +690,7 @@ function runtests(tests = ["all"], numcores = ceil(Int, Sys.CPU_CORES / 2)) catch buf = PipeBuffer() versioninfo(buf) - error("A test has failed. Please submit a bug report (https://github.com/JuliaLang/julia/issues)\n" * + error("A test has failed. Please submit a bug report (https://github.com/JuliaLang/julia/issues)\n" ++ "including error messages above and the output of versioninfo():\n$(readstring(buf))") end end diff --git a/base/libgit2/callbacks.jl b/base/libgit2/callbacks.jl index 0a78f48949f47..217f47658d005 100644 --- a/base/libgit2/callbacks.jl +++ b/base/libgit2/callbacks.jl @@ -205,7 +205,7 @@ function credentials_callback(libgit2credptr::Ptr{Ptr{Void}}, url_ptr::Cstring, # parse url for schema and host urlparts = match(URL_REGEX, url) - schema = urlparts[:scheme] === nothing ? "" : urlparts[:scheme] * "://" + schema = urlparts[:scheme] === nothing ? "" : urlparts[:scheme] ++ "://" urlusername = urlparts[:user] === nothing ? "" : urlparts[:user] host = urlparts[:host] @@ -241,7 +241,7 @@ function credentials_callback(libgit2credptr::Ptr{Ptr{Void}}, url_ptr::Cstring, # with the remote host. if err == 0 if explicit - warn("The explicitly provided credentials were incompatible with " * + warn("The explicitly provided credentials were incompatible with ", "the server's supported authentication methods") end err = Cint(Error.EAUTH) diff --git a/base/libgit2/utils.jl b/base/libgit2/utils.jl index 59b84bf905427..19e4e61b645f4 100644 --- a/base/libgit2/utils.jl +++ b/base/libgit2/utils.jl @@ -35,7 +35,7 @@ function prompt(msg::AbstractString; default::AbstractString="", password::Bool= if is_windows() && password error("Command line prompt not supported for password entry on windows. Use winprompt instead") end - msg = !isempty(default) ? msg*" [$default]:" : msg*":" + msg = !isempty(default) ? msg++" [$default]:" : msg++":" uinput = if password Base.getpass(msg) else diff --git a/base/libuv.jl b/base/libuv.jl index 702fad7392081..d9ef8e4eb6cbf 100644 --- a/base/libuv.jl +++ b/base/libuv.jl @@ -66,7 +66,7 @@ uverrorname(err::UVError) = uverrorname(err.code) uv_error(prefix::Symbol, c::Integer) = uv_error(string(prefix),c) uv_error(prefix::AbstractString, c::Integer) = c < 0 ? throw(UVError(prefix,c)) : nothing -show(io::IO, e::UVError) = print(io, e.prefix*": "*struverror(e)*" ("*uverrorname(e)*")") +show(io::IO, e::UVError) = print(io, e.prefix,": ",struverror(e)," (",uverrorname(e),")") ## event loop ## diff --git a/base/linalg/cholesky.jl b/base/linalg/cholesky.jl index 434a7fdbe5a5c..ebeeef443a40c 100644 --- a/base/linalg/cholesky.jl +++ b/base/linalg/cholesky.jl @@ -126,8 +126,8 @@ end chol!(x::Number, uplo) = ((C, info) = _chol!(x, uplo); @assertposdef C info) -non_hermitian_error(f) = throw(ArgumentError("matrix is not symmetric/" * - "Hermitian. This error can be avoided by calling $f(Hermitian(A)) " * +non_hermitian_error(f) = throw(ArgumentError("matrix is not symmetric/" ++ + "Hermitian. This error can be avoided by calling $f(Hermitian(A)) " ++ "which will ignore either the upper or lower triangle of the matrix.")) # chol!. Destructive methods for computing Cholesky factor of real symmetric or Hermitian diff --git a/base/linalg/generic.jl b/base/linalg/generic.jl index 9a020b5a0dece..689ca68d3d98e 100644 --- a/base/linalg/generic.jl +++ b/base/linalg/generic.jl @@ -1058,7 +1058,7 @@ function linreg(x::AbstractVector, y::AbstractVector) # b = cov(X, Y)/var(X) # a = mean(Y) - b*mean(X) if size(x) != size(y) - throw(DimensionMismatch("x has size $(size(x)) and y has size $(size(y)), " * + throw(DimensionMismatch("x has size $(size(x)) and y has size $(size(y)), " ++ "but these must be the same size")) end mx = mean(x) diff --git a/base/linalg/triangular.jl b/base/linalg/triangular.jl index a9935851177cc..3a8ef0b4b322a 100644 --- a/base/linalg/triangular.jl +++ b/base/linalg/triangular.jl @@ -130,7 +130,7 @@ getindex(A::UpperTriangular, i::Integer, j::Integer) = function setindex!(A::UpperTriangular, x, i::Integer, j::Integer) if i > j - x == 0 || throw(ArgumentError("cannot set index in the lower triangular part " * + x == 0 || throw(ArgumentError("cannot set index in the lower triangular part " ++ "($i, $j) of an UpperTriangular matrix to a nonzero value ($x)")) else A.data[i,j] = x @@ -140,10 +140,10 @@ end function setindex!(A::UnitUpperTriangular, x, i::Integer, j::Integer) if i > j - x == 0 || throw(ArgumentError("cannot set index in the lower triangular part " * + x == 0 || throw(ArgumentError("cannot set index in the lower triangular part " ++ "($i, $j) of a UnitUpperTriangular matrix to a nonzero value ($x)")) elseif i == j - x == 1 || throw(ArgumentError("cannot set index on the diagonal ($i, $j) " * + x == 1 || throw(ArgumentError("cannot set index on the diagonal ($i, $j) " ++ "of a UnitUpperTriangular matrix to a non-unit value ($x)")) else A.data[i,j] = x @@ -153,7 +153,7 @@ end function setindex!(A::LowerTriangular, x, i::Integer, j::Integer) if i < j - x == 0 || throw(ArgumentError("cannot set index in the upper triangular part " * + x == 0 || throw(ArgumentError("cannot set index in the upper triangular part " ++ "($i, $j) of a LowerTriangular matrix to a nonzero value ($x)")) else A.data[i,j] = x @@ -163,10 +163,10 @@ end function setindex!(A::UnitLowerTriangular, x, i::Integer, j::Integer) if i < j - x == 0 || throw(ArgumentError("cannot set index in the upper triangular part " * + x == 0 || throw(ArgumentError("cannot set index in the upper triangular part " ++ "($i, $j) of a UnitLowerTriangular matrix to a nonzero value ($x)")) elseif i == j - x == 1 || throw(ArgumentError("cannot set index on the diagonal ($i, $j) " * + x == 1 || throw(ArgumentError("cannot set index on the diagonal ($i, $j) " ++ "of a UnitLowerTriangular matrix to a non-unit value ($x)")) else A.data[i,j] = x diff --git a/base/loading.jl b/base/loading.jl index 1382f4f2a00ed..74a26eaf38cf5 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -140,7 +140,7 @@ function find_all_in_cache_path(mod::Symbol) name = string(mod) paths = String[] for prefix in LOAD_CACHE_PATH - path = joinpath(prefix, name*".ji") + path = joinpath(prefix, name++".ji") if isfile_casesensitive(path) push!(paths, path) end @@ -345,7 +345,7 @@ function require_modname(name::AbstractString) if endswith(name, ".jl") tmp = name[1:end-3] for prefix in LOAD_CACHE_PATH - path = joinpath(prefix, tmp*".ji") + path = joinpath(prefix, tmp++".ji") if isfile(path) return tmp end @@ -658,7 +658,7 @@ function compilecache(name::String) if !isdir(cachepath) mkpath(cachepath) end - cachefile::String = abspath(cachepath, name*".ji") + cachefile::String = abspath(cachepath, name++".ji") # build up the list of modules that we want the precompile process to preserve concrete_deps = copy(_concrete_dependencies) for existing in names(Main) diff --git a/base/markdown/Common/block.jl b/base/markdown/Common/block.jl index a0c4a095d3bae..e4f92b4c615bc 100644 --- a/base/markdown/Common/block.jl +++ b/base/markdown/Common/block.jl @@ -303,7 +303,7 @@ function list(stream::IO, block::MD) end else newline = false - if startswith(stream, " "^indent) + if startswith(stream, repeat(" ",indent)) # Indented text that is part of the current list item. print(buffer, readline(stream, chomp=false)) else diff --git a/base/markdown/GitHub/table.jl b/base/markdown/GitHub/table.jl index a8313e3fa6629..cd9b45924a2a1 100644 --- a/base/markdown/GitHub/table.jl +++ b/base/markdown/GitHub/table.jl @@ -91,15 +91,15 @@ function padcells!(rows, align; len = length, min = 0) for i = 1:length(rows), j = indices(rows[1],1) cell = rows[i][j] lpad, rpad = padding(len(cell), widths[j], align[j]) - rows[i][j] = " "^lpad * cell * " "^rpad + rows[i][j] = repeat(" ",lpad) ++ cell ++ repeat(" ",rpad) end return rows end _dash(width, align) = - align == :l ? ":" * "-"^width * " " : - align == :r ? " " * "-"^width * ":" : - align == :c ? ":" * "-"^width * ":" : + align == :l ? ":" ++ repeat("-",width) ++ " " : + align == :r ? " " ++ repeat("-",width) ++ ":" : + align == :c ? ":" ++ repeat("-",width) ++ ":" : throw(ArgumentError("Invalid alignment $align")) function plain(io::IO, md::Table) diff --git a/base/markdown/render/latex.jl b/base/markdown/render/latex.jl index fb0650c5d6603..9ef5ae0b3b4be 100644 --- a/base/markdown/render/latex.jl +++ b/base/markdown/render/latex.jl @@ -25,7 +25,7 @@ function latex(io::IO, content::Vector) end function latex(io::IO, header::Header{l}) where l - tag = l < 4 ? "sub"^(l-1) * "section" : "sub"^(l-4) * "paragraph" + tag = l < 4 ? repeat("sub",l-1) ++ "section" : repeat("sub",l-4) ++ "paragraph" wrapinline(io, tag) do latexinline(io, header.text) end diff --git a/base/markdown/render/plain.jl b/base/markdown/render/plain.jl index 5d50b5c2080f1..70027429d76a0 100644 --- a/base/markdown/render/plain.jl +++ b/base/markdown/render/plain.jl @@ -14,7 +14,7 @@ end plain(io::IO, md::MD) = plain(io, md.content) function plain(io::IO, header::Header{l}) where l - print(io, "#"^l*" ") + print(io, repeat("#",l)++" ") plaininline(io, header.text) println(io) end @@ -122,7 +122,7 @@ plaininline(io::IO, md::Italic) = plaininline(io, "*", md.text, "*") function plaininline(io::IO, md::Code) if contains(md.code, "`") n = maximum(length(m) for m in matchall(r"(`+)", md.code)) - s = "`"^((iseven(n) ? 1 : 2) + n) + s = repeat("`", (iseven(n) ? 1 : 2) + n) print(io, s, Base.startswith(md.code, "`") ? " " : "") print(io, md.code, endswith(md.code, "`") ? " " : "", s) else diff --git a/base/markdown/render/rst.jl b/base/markdown/render/rst.jl index d9fadc4e7910e..7eca9fc85bca2 100644 --- a/base/markdown/render/rst.jl +++ b/base/markdown/render/rst.jl @@ -42,7 +42,7 @@ function rst(io::IO, list::List) print(io, bullet) lines = split(rstrip(sprint(rst, item)), '\n') for (n, line) in enumerate(lines) - print(io, (n == 1 || isempty(line)) ? "" : " "^length(bullet), line) + print(io, (n == 1 || isempty(line)) ? "" : repeat(" ",length(bullet)), line) n < length(lines) && println(io) end println(io) diff --git a/base/markdown/render/terminal/formatting.jl b/base/markdown/render/terminal/formatting.jl index 36a4d390a7138..27a172bbc9010 100644 --- a/base/markdown/render/terminal/formatting.jl +++ b/base/markdown/render/terminal/formatting.jl @@ -72,7 +72,7 @@ function wrapped_lines(s::AbstractString; width = 80, i = 0) push!(lines, word) else i += word_length + 1 - lines[end] *= " " * word + lines[end] = lines[end] ++ " " ++ word end end return lines @@ -95,7 +95,7 @@ print_wrapped(f::Function, io::IO, args...; kws...) = print_wrapped(io, f, args. function print_centred(io::IO, s...; columns = 80, width = columns) lines = wrapped_lines(s..., width = width) for line in lines - print(io, " "^(div(columns-ansi_length(line), 2))) + print(io, repeat(" ",div(columns-ansi_length(line), 2))) println(io, line) end length(lines), length(pre) + length(lines[end]) @@ -103,5 +103,5 @@ end function centred(s, columns) pad = div(columns - ansi_length(s), 2) - " "^pad * s + repeat(" ",pad) ++ s end diff --git a/base/markdown/render/terminal/render.jl b/base/markdown/render/terminal/render.jl index f7313dc36b23f..c872d6bcd32ac 100644 --- a/base/markdown/render/terminal/render.jl +++ b/base/markdown/render/terminal/render.jl @@ -17,8 +17,8 @@ end term(io::IO, md::MD, columns = cols(io)) = term(io, md.content, columns) function term(io::IO, md::Paragraph, columns) - print(io, " "^margin) - print_wrapped(io, width = columns-2margin, pre = " "^margin) do io + print(io, repeat(" ",margin)) + print_wrapped(io, width = columns-2margin, pre = repeat(" ",margin)) do io terminline(io, md.content) end end @@ -26,34 +26,34 @@ end function term(io::IO, md::BlockQuote, columns) s = sprint(term, md.content, columns - 10) for line in split(rstrip(s), "\n") - println(io, " "^margin, "|", line) + println(io, repeat(" ",margin), "|", line) end end function term(io::IO, md::Admonition, columns) - print(io, " "^margin, "| ") + print(io, repeat(" ",margin), "| ") with_output_format(:bold, print, io, isempty(md.title) ? md.category : md.title) - println(io, "\n", " "^margin, "|") + println(io, "\n", repeat(" ",margin), "|") s = sprint(term, md.content, columns - 10) for line in split(rstrip(s), "\n") - println(io, " "^margin, "|", line) + println(io, repeat(" ",margin), "|", line) end end function term(io::IO, f::Footnote, columns) - print(io, " "^margin, "| ") + print(io, repeat(" ",margin), "| ") with_output_format(:bold, print, io, "[^$(f.id)]") - println(io, "\n", " "^margin, "|") + println(io, "\n", repeat(" ",margin), "|") s = sprint(term, f.text, columns - 10) for line in split(rstrip(s), "\n") - println(io, " "^margin, "|", line) + println(io, repeat(" ",margin), "|", line) end end function term(io::IO, md::List, columns) for (i, point) in enumerate(md.items) - print(io, " "^2margin, isordered(md) ? "$(i + md.ordered - 1). " : "• ") - print_wrapped(io, width = columns-(4margin+2), pre = " "^(2margin+2), + print(io, repeat(" ",2margin), isordered(md) ? "$(i + md.ordered - 1). " : "• ") + print_wrapped(io, width = columns-(4margin+2), pre = repeat(" ",2margin+2), i = 2margin+2) do io term(io, point, columns - 10) end @@ -63,14 +63,14 @@ end function _term_header(io::IO, md, char, columns) text = terminline(md.text) with_output_format(:bold, io) do io - print(io, " "^(2margin), " ") + print(io, repeat(" ",2margin), " ") line_no, lastline_width = print_wrapped(io, text, width=columns - 4margin; pre=" ") line_width = min(1 + lastline_width, columns) if line_no > 1 line_width = max(line_width, div(columns, 3)) end - char != ' ' && println(io, " "^(2margin), string(char) ^ line_width) + char != ' ' && println(io, repeat(" ",2margin), string(char) ^ line_width) end end @@ -85,7 +85,7 @@ end function term(io::IO, md::Code, columns) with_output_format(:cyan, io) do io for line in lines(md.code) - print(io, " "^margin) + print(io, repeat(" ",margin)) println(io, line) end end @@ -96,7 +96,7 @@ function term(io::IO, br::LineBreak, columns) end function term(io::IO, br::HorizontalRule, columns) - println(io, " " ^ margin, "-" ^ (columns - 2margin)) + println(io, repeat(" ",margin), repeat("-", columns - 2margin)) end term(io::IO, x, _) = show(io, MIME"text/plain"(), x) diff --git a/base/meta.jl b/base/meta.jl index bbe4c3f49bde6..8c27d738eff4f 100644 --- a/base/meta.jl +++ b/base/meta.jl @@ -28,20 +28,20 @@ const sexpr_indent_width = 2 function show_sexpr(io::IO, ex::QuoteNode, indent::Int) inner = indent + sexpr_indent_width - print(io, "(:quote, #QuoteNode\n", " "^inner) + print(io, "(:quote, #QuoteNode\n", repeat(" ",inner)) show_sexpr(io, ex.value, inner) - print(io, '\n', " "^indent, ')') + print(io, '\n', repeat(" ",indent), ')') end function show_sexpr(io::IO, ex::Expr, indent::Int) inner = indent + sexpr_indent_width print(io, '(') show_sexpr(io, ex.head, inner) for arg in ex.args - print(io, ex.head === :block ? ",\n"*" "^inner : ", ") + print(io, ex.head === :block ? ",\n"++repeat(" ",inner) : ", ") show_sexpr(io, arg, inner) end if isempty(ex.args); print(io, ",)") - else print(io, (ex.head === :block ? "\n"*" "^indent : ""), ')') + else print(io, (ex.head === :block ? "\n"++repeat(" ",indent) : ""), ')') end end diff --git a/base/methodshow.jl b/base/methodshow.jl index d6b223da5f1ab..2098dd14778ce 100644 --- a/base/methodshow.jl +++ b/base/methodshow.jl @@ -34,7 +34,7 @@ function argtype_decl(env, n, sig::DataType, i::Int, nargs, isva::Bool) # -> (ar if tt === Any || (isa(tt, TypeVar) && (tt === v1 || tt === v2)) return string(s, "..."), "" else - return s, string_with_env(env, tt) * "..." + return s, string_with_env(env, tt) ++ "..." end end return s, string_with_env(env, "Vararg{", tt, ",", tn, "}") @@ -118,7 +118,7 @@ function show(io::IO, m::Method; kwtype::Nullable{DataType}=Nullable{DataType}() print(io, "(", d1[1], "::", d1[2], ")") end print(io, "(") - join(io, [isempty(d[2]) ? d[1] : d[1]*"::"*d[2] for d in decls[2:end]], + join(io, [isempty(d[2]) ? d[1] : d[1]++"::"++d[2] for d in decls[2:end]], ", ", ", ") if !isnull(kwtype) kwargs = kwarg_decl(m, get(kwtype)) @@ -185,7 +185,7 @@ function inbase(m::Module) parent === m ? false : inbase(parent) end end -fileurl(file) = let f = find_source_file(file); f === nothing ? "" : "file://"*f; end +fileurl(file) = let f = find_source_file(file); f === nothing ? "" : "file://"++f; end function url(m::Method) M = m.module @@ -211,7 +211,7 @@ function url(m::Method) commit = string(LibGit2.head_oid(repo)) root = LibGit2.path(repo) if startswith(file, root) || startswith(realpath(file), root) - "https://github.com/$u/tree/$commit/"*file[length(root)+1:end]*"#L$line" + "https://github.com/$u/tree/$commit/"++file[length(root)+1:end]++"#L$line" else fileurl(file) end @@ -248,7 +248,7 @@ function show(io::IO, ::MIME"text/html", m::Method; kwtype::Nullable{DataType}=N print(io,"") end print(io, "(") - join(io, [isempty(d[2]) ? d[1] : d[1]*"::"*d[2]*"" + join(io, [isempty(d[2]) ? d[1] : d[1]++"::"++d[2]++"" for d in decls[2:end]], ", ", ", ") if !isnull(kwtype) kwargs = kwarg_decl(m, get(kwtype)) diff --git a/base/path.jl b/base/path.jl index 28ac0b520e85d..541edef0cbcbc 100644 --- a/base/path.jl +++ b/base/path.jl @@ -178,7 +178,7 @@ function splitext(path::String) a, b = splitdrive(path) m = match(path_ext_splitter, b) m === nothing && return (path,"") - a*m.captures[1], String(m.captures[2]) + a ++ m.captures[1], String(m.captures[2]) end function pathsep(paths::AbstractString...) @@ -252,10 +252,10 @@ function normpath(path::String) end path = join(parts, path_separator) if isabs - path = path_separator*path + path = path_separator ++ path end if isdir && !isdirpath(path) - path *= path_separator + path = path ++ path_separator end string(drive,path) end @@ -333,7 +333,7 @@ function expanduser(path::AbstractString) if c != '~' return path end if done(path,i) return homedir() end c, j = next(path,i) - if c == '/' return homedir()*path[i:end] end + if c == '/' return homedir() ++ path[i:end] end throw(ArgumentError("~user tilde expansion not yet implemented")) end end @@ -373,10 +373,10 @@ function relpath(path::String, startpath::String = ".") pathpart = join(path_arr[i+1:findlast(x -> !isempty(x), path_arr)], path_separator) prefix_num = findlast(x -> !isempty(x), start_arr) - i - 1 if prefix_num >= 0 - prefix = pardir * path_separator + prefix = pardir ++ path_separator relpath_ = isempty(pathpart) ? - (prefix^prefix_num) * pardir : - (prefix^prefix_num) * pardir * path_separator * pathpart + repeat(prefix,prefix_num) ++ pardir : + repeat(prefix,prefix_num) ++ pardir ++ path_separator ++ pathpart else relpath_ = pathpart end diff --git a/base/pkg/entry.jl b/base/pkg/entry.jl index 41f638102cfdb..ddefde0c0cde2 100644 --- a/base/pkg/entry.jl +++ b/base/pkg/entry.jl @@ -305,7 +305,7 @@ function pin(pkg::AbstractString, head::AbstractString) # note: changing the following naming scheme requires a corresponding change in Read.ispinned() branch = "pinned.$(string(id)[1:8]).tmp" if LibGit2.isattached(repo) && LibGit2.branch(repo) == branch - info("Package $pkg is already pinned" * (isempty(head) ? "" : " to the selected commit")) + info("Package $pkg is already pinned", (isempty(head) ? "" : " to the selected commit")) should_resolve = false return end @@ -313,7 +313,7 @@ function pin(pkg::AbstractString, head::AbstractString) try if !isnull(ref) if LibGit2.revparseid(repo, branch) != id - throw(PkgError("Package $pkg: existing branch $branch has " * + throw(PkgError("Package $pkg: existing branch $branch has " ++ "been edited and doesn't correspond to its original commit")) end info("Package $pkg: checking out existing branch $branch") @@ -375,8 +375,8 @@ function update(branch::AbstractString, upkgs::Set{String}) end catch err cex = CapturedException(err, catch_backtrace()) - throw(PkgError("METADATA cannot be updated. Resolve problems manually in " * - Pkg.dir("METADATA") * ".", cex)) + throw(PkgError("METADATA cannot be updated. Resolve problems manually in " ++ + Pkg.dir("METADATA") ++ ".", cex)) end end deferred_errors = CompositeException() @@ -394,8 +394,8 @@ function update(branch::AbstractString, upkgs::Set{String}) reqs = Reqs.parse("REQUIRE") if !isempty(upkgs) for (pkg, (v,f)) in instd - satisfies(pkg, v, reqs) || throw(PkgError("Package $pkg: current " * - "package status does not satisfy the requirements, cannot do " * + satisfies(pkg, v, reqs) || throw(PkgError("Package $pkg: current " ++ + "package status does not satisfy the requirements, cannot do " ++ "a partial update; use `Pkg.update()`")) end end @@ -483,11 +483,11 @@ function resolve( for pkg in keys(reqs) if !haskey(deps,pkg) if "julia" in conflicts[pkg] - throw(PkgError("$pkg can't be installed because it has no versions that support $VERSION " * + throw(PkgError("$pkg can't be installed because it has no versions that support $VERSION " ++ "of julia. You may need to update METADATA by running `Pkg.update()`")) else sconflicts = join(conflicts[pkg], ", ", " and ") - throw(PkgError("$pkg's requirements can't be satisfied because " * + throw(PkgError("$pkg's requirements can't be satisfied because " ++ "of the following fixed packages: $sconflicts")) end end diff --git a/base/pkg/read.jl b/base/pkg/read.jl index dc4046fa3db92..60927125235f6 100644 --- a/base/pkg/read.jl +++ b/base/pkg/read.jl @@ -245,7 +245,7 @@ function issue_url(pkg::AbstractString) ispath(pkg,".git") || return "" m = match(LibGit2.GITHUB_REGEX, url(pkg)) m === nothing && return "" - return "https://github.com/" * m.captures[1] * "/issues" + return "https://github.com/" ++ m.captures[1] ++ "/issues" end end # module diff --git a/base/pkg/resolve.jl b/base/pkg/resolve.jl index a8481a9aee5c0..0a0caa168804c 100644 --- a/base/pkg/resolve.jl +++ b/base/pkg/resolve.jl @@ -44,7 +44,7 @@ function resolve(reqs::Requires, deps::Dict{String,Dict{VersionNumber,Available} environment variable) """ end - ## info("ERROR MESSAGE:\n" * msg) + ## info("ERROR MESSAGE:\n", msg) throw(PkgError(msg)) end @@ -101,7 +101,7 @@ function sanity_check(deps::Dict{String,Dict{VersionNumber,Available}}, sub_deps = Query.prune_dependencies(sub_reqs, deps) catch err isa(err, PkgError) || rethrow(err) - ## info("ERROR MESSAGE:\n" * err.msg) + ## info("ERROR MESSAGE:\n", err.msg) for vneq in eq_classes[p][vn] push!(problematic, (p, vneq, "")) end diff --git a/base/printf.jl b/base/printf.jl index b743ab6e05529..2d34625ad33cc 100644 --- a/base/printf.jl +++ b/base/printf.jl @@ -62,7 +62,7 @@ function parse(s::AbstractString) j -= 1 break end - list[i] *= list[j] + list[i] = list[i] ++ list[j] end deleteat!(list,i+1:j) end diff --git a/base/process.jl b/base/process.jl index ea421ce4e729f..f4e335d63713b 100644 --- a/base/process.jl +++ b/base/process.jl @@ -206,10 +206,10 @@ end byteenv(env::AbstractArray{<:AbstractString}) = String[cstr(x) for x in env] byteenv(env::Associative) = - String[cstr(string(k)*"="*string(v)) for (k,v) in env] + String[cstr(string(k)++"="++string(v)) for (k,v) in env] byteenv(env::Void) = nothing byteenv(env::Union{AbstractVector{Pair{T}}, Tuple{Vararg{Pair{T}}}}) where {T<:AbstractString} = - String[cstr(k*"="*string(v)) for (k,v) in env] + String[cstr(k++"="++string(v)) for (k,v) in env] """ setenv(command::Cmd, env; dir="") @@ -774,9 +774,9 @@ process_signaled(s::Process) = (s.termsignal > 0) function process_status(s::Process) process_running(s) ? "ProcessRunning" : - process_signaled(s) ? "ProcessSignaled("*string(s.termsignal)*")" : - #process_stopped(s) ? "ProcessStopped("*string(process_stop_signal(s))*")" : - process_exited(s) ? "ProcessExited("*string(s.exitcode)*")" : + process_signaled(s) ? "ProcessSignaled("*string(s.termsignal)++")" : + #process_stopped(s) ? "ProcessStopped("*string(process_stop_signal(s))++")" : + process_exited(s) ? "ProcessExited("*string(s.exitcode)++")" : error("process status error") end diff --git a/base/profile.jl b/base/profile.jl index a5afcb3fdfb62..3a4bf3f8cf18c 100644 --- a/base/profile.jl +++ b/base/profile.jl @@ -474,7 +474,7 @@ function tree_format(lilist::Vector{StackFrame}, counts::Vector{Int}, level::Int for i = 1:length(lilist) li = lilist[i] if li != UNKNOWN - base = " "^nindent + base = repeat(" ",nindent) if showextra base = string(base, "+", nextra, " ") end diff --git a/base/promotion.jl b/base/promotion.jl index e5f2bdd6f80de..fc681ee282139 100644 --- a/base/promotion.jl +++ b/base/promotion.jl @@ -360,3 +360,26 @@ minmax(x::Real) = (x, x) max(x::T, y::T) where {T<:Real} = select_value(y < x, x, y) min(x::T, y::T) where {T<:Real} = select_value(y < x, y, x) minmax(x::T, y::T) where {T<:Real} = y < x ? (y, x) : (x, y) + +# Concatenation via a++b++... -> concat(concate_typeof(a,b,..), a,b,...): +# Similar to promote_rule, you can define a concat_rule(T, S) to +# determine how instances of two types T and S are concatenated. The +# default is "Bottom", which gets turned into a vcat call in abstractarray.jl. +concat_typeof() = concat_type() +concat_typeof(x) = concat_type(typeof(x)) +concat_typeof(x, xs...) = (@_inline_meta; concat_type(typeof(x), concat_typeof(xs...))) +concat_type() = Bottom +concat_type(T, S...) = (@_inline_meta; concat_type(T, concat_type(S...))) +concat_type(::Type{Bottom}, ::Type{Bottom}) = Bottom +concat_type(::Type{T}, ::Type{Bottom}) where {T} = T +concat_type(::Type{Bottom}, ::Type{T}) where {T} = T +function concat_type(::Type{T}, ::Type{S}) where {T,S} + @_inline_meta + concat_result(concat_rule(T,S), concat_rule(S,T)) +end +concat_result(::Type{T},::Type{T}) where {T} = (@_inline_meta; T) +concat_result(::Type{Bottom},::Type{T}) where {T} = (@_inline_meta; T) +concat_result(::Type{T},::Type{Bottom}) where {T} = (@_inline_meta; T) +concat_result(::Type{Bottom},::Type{Bottom}) = (@_inline_meta; Bottom) +concat_result(::Type{T},::Type{S}) where {T,S} = (@_inline_meta; Bottom) +concat_rule(T, S) = (@_inline_meta; Bottom) diff --git a/base/reflection.jl b/base/reflection.jl index a13fc7e9bdb4a..f64e3f3a64d33 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -695,7 +695,7 @@ function _dump_function_linfo(linfo::Core.MethodInstance, world::UInt, native::B end # TODO: use jl_is_cacheable_sig instead of isleaftype - isleaftype(linfo.specTypes) || (str = "; WARNING: This code may not match what actually runs.\n" * str) + isleaftype(linfo.specTypes) || (str = "; WARNING: This code may not match what actually runs.\n" ++ str) return str end diff --git a/base/repl/LineEdit.jl b/base/repl/LineEdit.jl index 4beccbff1841b..d3c81d77975f9 100644 --- a/base/repl/LineEdit.jl +++ b/base/repl/LineEdit.jl @@ -693,7 +693,7 @@ function add_nested_key!(keymap::Dict, key, value; override = false) break else if !isa(keymap[c], Dict) - error("Conflicting definitions for keyseq " * escape_string(key) * " within one keymap") + error("Conflicting definitions for keyseq ", escape_string(key), " within one keymap") end end elseif done(key, i) @@ -868,7 +868,7 @@ function keymap_merge(target,source) while isa(value, Union{Char,AbstractString}) value = normalize_key(value) if value in visited - error("Eager redirection cycle detected for key " * escape_string(key)) + error("Eager redirection cycle detected for key ", escape_string(key)) end push!(visited,value) if !haskey(source,value) @@ -880,7 +880,7 @@ function keymap_merge(target,source) if isa(value, Union{Char,AbstractString}) value = getEntry(ret, value) if value === nothing - error("Could not find redirected value " * escape_string(source[key])) + error("Could not find redirected value ", escape_string(source[key])) end end add_nested_key!(ret, key, value; override = true) @@ -1321,7 +1321,7 @@ function bracketed_paste(s) indent = Base.indentation(input; tabwidth=tabwidth)[1] input = Base.unindent(input, indent; tabwidth=tabwidth) end - return replace(input, '\t', " "^tabwidth) + return replace(input, '\t', repeat(" ",tabwidth)) end const default_keymap = @@ -1341,7 +1341,7 @@ AnyDict( # after a space, e.g., `cd `, while still # allowing multiple indent levels (c == UInt8(' ') && i > 3 && buf.data[i-1] == UInt8(' ')) - edit_insert(s, " "^4) + edit_insert(s, repeat(" ",4)) return end end diff --git a/base/repl/REPLCompletions.jl b/base/repl/REPLCompletions.jl index 4a80c24991cf3..cdebca62a65a0 100644 --- a/base/repl/REPLCompletions.jl +++ b/base/repl/REPLCompletions.jl @@ -400,9 +400,9 @@ end function dict_identifier_key(str,tag) if tag === :string - str_close = str*"\"" + str_close = str++"\"" elseif tag === :cmd - str_close = str*"`" + str_close = str++"`" else str_close = str end @@ -479,7 +479,7 @@ function completions(string, pos) if inc_tag == :other && should_method_complete(partial) frange, method_name_end = find_start_brace(partial) ex = Base.syntax_deprecation_warnings(false) do - parse(partial[frange] * ")", raise=false) + parse(partial[frange] ++ ")", raise=false) end if isa(ex, Expr) && ex.head==:call return complete_methods(ex), start(frange):method_name_end, false diff --git a/base/repl/emoji_symbols.jl b/base/repl/emoji_symbols.jl index f8a5043f19f36..b48473b641fe2 100644 --- a/base/repl/emoji_symbols.jl +++ b/base/repl/emoji_symbols.jl @@ -6,7 +6,7 @@ emojis = JSON.parsefile(download("https://raw.githubusercontent.com/iamcal/emoji result = Dict() for emj in emojis - name = "\\:" * emj["short_name"] * ":" + name = "\\:" ++ emj["short_name"] ++ ":" unicode = emj["unified"] if '-' in unicode continue diff --git a/base/sharedarray.jl b/base/sharedarray.jl index 6ef164720b836..45c167deb400d 100644 --- a/base/sharedarray.jl +++ b/base/sharedarray.jl @@ -129,7 +129,7 @@ function SharedArray{T,N}(dims::Dims{N}; init=false, pids=Int[]) where {T,N} else rc = remotecall_fetch(shm_unlink, shmmem_create_pid, shm_seg_name) end - systemerror("Error unlinking shmem segment " * shm_seg_name, rc != 0) + systemerror("Error unlinking shmem segment " ++ shm_seg_name, rc != 0) end S = SharedArray{T,N}(dims, pids, refs, shm_seg_name, s) initialize_shared_array(S, onlocalhost, init, pids) @@ -647,7 +647,7 @@ shm_unlink(shm_seg_name) = 0 else # !windows function _shm_mmap_array(T, dims, shm_seg_name, mode) fd_mem = shm_open(shm_seg_name, mode, S_IRUSR | S_IWUSR) - systemerror("shm_open() failed for " * shm_seg_name, fd_mem < 0) + systemerror("shm_open() failed for " ++ shm_seg_name, fd_mem < 0) s = fdio(fd_mem, true) @@ -655,7 +655,7 @@ function _shm_mmap_array(T, dims, shm_seg_name, mode) # and only at creation time if (mode & JL_O_CREAT) == JL_O_CREAT rc = ccall(:jl_ftruncate, Cint, (Cint, Int64), fd_mem, prod(dims)*sizeof(T)) - systemerror("ftruncate() failed for shm segment " * shm_seg_name, rc != 0) + systemerror("ftruncate() failed for shm segment " ++ shm_seg_name, rc != 0) end Mmap.mmap(s, Array{T,length(dims)}, dims, zero(Int64); grow=false) diff --git a/base/show.jl b/base/show.jl index b7b1a77032257..f7b2d44efffb3 100644 --- a/base/show.jl +++ b/base/show.jl @@ -249,7 +249,7 @@ show_supertypes(typ::DataType) = show_supertypes(STDOUT, typ) macro show(exs...) blk = Expr(:block) for ex in exs - push!(blk.args, :(print($(sprint(show_unquoted,ex)*" = ")))) + push!(blk.args, :(print($(sprint(show_unquoted,ex)++" = ")))) push!(blk.args, :(show(STDOUT, "text/plain", begin value=$(esc(ex)) end))) push!(blk.args, :(println())) end @@ -551,10 +551,10 @@ function show_block(io::IO, head, args::Vector, body, indent::Int) ind = head === :module || head === :baremodule ? indent : indent + indent_width exs = (is_expr(body, :block) || is_expr(body, :body)) ? body.args : Any[body] for ex in exs - print(io, '\n', " "^ind) + print(io, '\n', repeat(" ",ind)) show_unquoted(io, ex, ind, -1) end - print(io, '\n', " "^indent) + print(io, '\n', repeat(" ",indent)) end show_block(io::IO,head, block,i::Int) = show_block(io,head, [], block,i) function show_block(io::IO, head, arg, block, i::Int) diff --git a/base/sparse/cholmod.jl b/base/sparse/cholmod.jl index 08eec5cdac939..064a6f45579ae 100644 --- a/base/sparse/cholmod.jl +++ b/base/sparse/cholmod.jl @@ -240,7 +240,7 @@ mutable struct Sparse{Tv<:VTypes} <: AbstractSparseMatrix{Tv,SuiteSparse_long} p::Ptr{C_Sparse{Tv}} function Sparse{Tv}(p::Ptr{C_Sparse{Tv}}) where Tv<:VTypes if p == C_NULL - throw(ArgumentError("sparse matrix construction failed for " * + throw(ArgumentError("sparse matrix construction failed for " ++ "unknown reasons. Please submit a bug report.")) end new(p) @@ -319,7 +319,7 @@ mutable struct Factor{Tv} <: Factorization{Tv} p::Ptr{C_Factor{Tv}} function Factor{Tv}(p::Ptr{C_Factor{Tv}}) where Tv if p == C_NULL - throw(ArgumentError("factorization construction failed for " * + throw(ArgumentError("factorization construction failed for " ++ "unknown reasons. Please submit a bug report.")) end new(p) @@ -333,7 +333,7 @@ Factor(p::Ptr{C_Factor{Tv}}) where {Tv<:VTypes} = Factor{Tv}(p) # when serialized so this can happen when mutiple processes are in use. function get(p::Ptr{T}) where T<:SuiteSparseStruct if p == C_NULL - throw(ArgumentError("pointer to the $T object is null. This can " * + throw(ArgumentError("pointer to the $T object is null. This can " ++ "happen if the object has been serialized.")) else return p @@ -687,16 +687,16 @@ function scale!(S::Dense{Tv}, scale::Integer, A::Sparse{Tv}) where Tv<:VRealType if scale == SCALAR && sS.nrow != 1 throw(DimensionMismatch("scaling argument must have length one")) elseif scale == ROW && sS.nrow*sS.ncol != sA.nrow - throw(DimensionMismatch("scaling vector has length $(sS.nrow*sS.ncol), " * + throw(DimensionMismatch("scaling vector has length $(sS.nrow*sS.ncol), " ++ "but matrix has $(sA.nrow) rows.")) elseif scale == COL && sS.nrow*sS.ncol != sA.ncol - throw(DimensionMismatch("scaling vector has length $(sS.nrow*sS.ncol), " * + throw(DimensionMismatch("scaling vector has length $(sS.nrow*sS.ncol), " ++ "but matrix has $(sA.ncol) columns")) elseif scale == SYM if sA.nrow != sA.ncol throw(DimensionMismatch("matrix must be square")) elseif sS.nrow*sS.ncol != sA.nrow - throw(DimensionMismatch("scaling vector has length $(sS.nrow*sS.ncol), " * + throw(DimensionMismatch("scaling vector has length $(sS.nrow*sS.ncol), " ++ "but matrix has $(sA.ncol) columns and rows")) end end @@ -786,7 +786,7 @@ end function solve(sys::Integer, F::Factor{Tv}, B::Dense{Tv}) where Tv<:VTypes if size(F,1) != size(B,1) - throw(DimensionMismatch("LHS and RHS should have the same number of rows. " * + throw(DimensionMismatch("LHS and RHS should have the same number of rows. " ++ "LHS has $(size(F,1)) rows, but RHS has $(size(B,1)) rows.")) end d = Dense(ccall((@cholmod_name("solve", SuiteSparse_long),:libcholmod), Ptr{C_Dense{Tv}}, @@ -798,7 +798,7 @@ end function spsolve(sys::Integer, F::Factor{Tv}, B::Sparse{Tv}) where Tv<:VTypes if size(F,1) != size(B,1) - throw(DimensionMismatch("LHS and RHS should have the same number of rows. " * + throw(DimensionMismatch("LHS and RHS should have the same number of rows. " ++ "LHS has $(size(F,1)) rows, but RHS has $(size(B,1)) rows.")) end s = Sparse(ccall((@cholmod_name("spsolve", SuiteSparse_long),:libcholmod), @@ -970,7 +970,7 @@ end # Useful when reading in files, but not type stable function convert(::Type{Sparse}, p::Ptr{C_SparseVoid}) if p == C_NULL - throw(ArgumentError("sparse matrix construction failed for " * + throw(ArgumentError("sparse matrix construction failed for " ++ "unknown reasons. Please submit a bug report.")) end @@ -979,11 +979,11 @@ function convert(::Type{Sparse}, p::Ptr{C_SparseVoid}) # Check integer type if s.itype == INT free_sparse!(p) - throw(CHOLMODException("the value of itype was $s.itype. " * + throw(CHOLMODException("the value of itype was $s.itype. " ++ "Only integer type of $SuiteSparse_long is supported.")) elseif s.itype == INTLONG free_sparse!(p) - throw(CHOLMODException("the value of itype was $s.itype. This combination " * + throw(CHOLMODException("the value of itype was $s.itype. This combination " ++ "of integer types shouldn't happen. Please submit a bug report.")) elseif s.itype != LONG # must be s.itype == LONG free_sparse!(p) @@ -1062,7 +1062,7 @@ convert(::Type{Vector}, D::Dense{T}) where {T} = convert(Vector{T}, D) function convert(::Type{SparseMatrixCSC{Tv,SuiteSparse_long}}, A::Sparse{Tv}) where Tv s = unsafe_load(A.p) if s.stype != 0 - throw(ArgumentError("matrix has stype != 0. Convert to matrix " * + throw(ArgumentError("matrix has stype != 0. Convert to matrix " ++ "with stype == 0 before converting to SparseMatrixCSC")) end diff --git a/base/sparse/sparsevector.jl b/base/sparse/sparsevector.jl index 0a540f21d4252..0227b871c0eec 100644 --- a/base/sparse/sparsevector.jl +++ b/base/sparse/sparsevector.jl @@ -770,7 +770,7 @@ function show(io::IOContext, x::AbstractSparseVector) end k != length(nzind) && println(io) elseif k == half_screen_rows - println(io, " ", " "^pad, " \u22ee") + println(io, " ", repeat(" ",pad), " \u22ee") end end end diff --git a/base/sparse/umfpack.jl b/base/sparse/umfpack.jl index d123ffe04581b..27bd814de9732 100644 --- a/base/sparse/umfpack.jl +++ b/base/sparse/umfpack.jl @@ -179,7 +179,7 @@ end ## Wrappers for UMFPACK functions # generate the name of the C function according to the value and integer types -umf_nm(nm,Tv,Ti) = "umfpack_" * (Tv == :Float64 ? "d" : "z") * (Ti == :Int64 ? "l_" : "i_") * nm +umf_nm(nm,Tv,Ti) = "umfpack_" ++ (Tv == :Float64 ? "d" : "z") ++ (Ti == :Int64 ? "l_" : "i_") ++ nm for itype in UmfpackIndexTypes sym_r = umf_nm("symbolic", :Float64, itype) diff --git a/base/strings/basic.jl b/base/strings/basic.jl index e31b2218de920..53d29a42c35a2 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -55,21 +55,9 @@ sizeof(s::AbstractString) = error("type $(typeof(s)) has no canonical binary rep eltype(::Type{<:AbstractString}) = Char -""" -``` -*(s::AbstractString, t::AbstractString) -``` - -Concatenate strings. The `*` operator is an alias to this function. - -```jldoctest -julia> "Hello " * "world" -"Hello world" -``` -""" -(*)(s1::AbstractString, ss::AbstractString...) = string(s1, ss...) - -one(::Union{T,Type{T}}) where {T<:AbstractString} = convert(T, "") +# make ++ concatenate strings [but string++array = vcat(string,array)] +concat(::Type{String}, X...) = string(X...) +concat_rule(::Type{<:AbstractString}, T) = (@_inline_meta; String) length(s::DirectIndexString) = endof(s) diff --git a/base/strings/types.jl b/base/strings/types.jl index 587af56c4015d..b44a97d31585e 100644 --- a/base/strings/types.jl +++ b/base/strings/types.jl @@ -133,25 +133,22 @@ reverseind(s::RevString, i::Integer) = endof(s) - i + 1 reverseind(s::SubString{String}, i::Integer) = reverseind(s.string, nextind(s.string, endof(s.string))-s.offset-s.endof+i-1) - s.offset -function repeat(s::AbstractString, r::Integer) - r < 0 ? throw(ArgumentError("can't repeat a string $r times")) : - r == 0 ? "" : - r == 1 ? s : - repeat(convert(String, s), r) -end - """ - ^(s::AbstractString, n::Integer) + repeat(s::AbstractString, n::Integer) -Repeat `n` times the string `s`. -The [`repeat`](@ref) function is an alias to this operator. +Construct a new string from `s` by repeating it `n` times. ```jldoctest -julia> "Test "^3 +julia> repeat("Test ",3) "Test Test Test " ``` """ -(^)(s::AbstractString, r::Integer) = repeat(s,r) +function repeat(s::AbstractString, r::Integer) + r < 0 ? throw(ArgumentError("can't repeat a string $r times")) : + r == 0 ? "" : + r == 1 ? s : + repeat(convert(String, s), r) +end pointer(x::SubString{String}) = pointer(x.string) + x.offset pointer(x::SubString{String}, i::Integer) = pointer(x.string) + x.offset + (i-1) diff --git a/base/strings/util.jl b/base/strings/util.jl index c4c4459545128..5a8cbffdbed9e 100644 --- a/base/strings/util.jl +++ b/base/strings/util.jl @@ -200,12 +200,12 @@ function lpad(s::AbstractString, n::Integer, p::AbstractString=" ") (m <= 0) && (return s) l = strwidth(p) if l==1 - return string(p^m, s) + return string(repeat(p,m), s) end q = div(m,l) r = m - q*l i = r != 0 ? chr2ind(p, r) : -1 - string(p^q, p[1:i], s) + string(repeat(p,q), p[1:i], s) end function rpad(s::AbstractString, n::Integer, p::AbstractString=" ") @@ -213,12 +213,12 @@ function rpad(s::AbstractString, n::Integer, p::AbstractString=" ") (m <= 0) && (return s) l = strwidth(p) if l==1 - return string(s, p^m) + return string(s, repeat(p,m)) end q = div(m,l) r = m - q*l i = r != 0 ? chr2ind(p, r) : -1 - string(s, p^q, p[1:i]) + string(s, repeat(p,q), p[1:i]) end """ diff --git a/base/test.jl b/base/test.jl index c841552bb9a88..88d6cd06c8846 100644 --- a/base/test.jl +++ b/base/test.jl @@ -754,7 +754,7 @@ function print_counts(ts::DefaultTestSet, depth, align, subtotal = passes + fails + errors + broken + c_passes + c_fails + c_errors + c_broken # Print test set header, with an alignment that ensures all # the test results appear above each other - print(rpad(string(" "^depth, ts.description), align, " "), " | ") + print(rpad(string(repeat(" ",depth), ts.description), align, " "), " | ") np = passes + c_passes if np > 0 diff --git a/base/version.jl b/base/version.jl index 08938b3f48af9..4043db978427c 100644 --- a/base/version.jl +++ b/base/version.jl @@ -250,10 +250,10 @@ function banner(io::IO = STDOUT) c = text_colors tx = c[:normal] # text jl = c[:normal] # julia - d1 = c[:bold] * c[:blue] # first dot - d2 = c[:bold] * c[:red] # second dot - d3 = c[:bold] * c[:green] # third dot - d4 = c[:bold] * c[:magenta] # fourth dot + d1 = c[:bold] ++ c[:blue] # first dot + d2 = c[:bold] ++ c[:red] # second dot + d3 = c[:bold] ++ c[:green] # third dot + d4 = c[:bold] ++ c[:magenta] # fourth dot print(io,""" $(d3)_$(tx) $(d1)_$(tx) $(jl)_$(tx) $(d2)_$(d3)(_)$(d4)_$(tx) | A fresh approach to technical computing diff --git a/contrib/julia-config.jl b/contrib/julia-config.jl index 2a177240d536f..9034f81b9432e 100755 --- a/contrib/julia-config.jl +++ b/contrib/julia-config.jl @@ -36,9 +36,9 @@ end function ldflags() fl = "-L$(shell_escape(libDir()))" if is_windows() - fl = fl * " -Wl,--stack,8388608" + fl = fl ++ " -Wl,--stack,8388608" elseif is_linux() - fl = fl * " -Wl,--export-dynamic" + fl = fl ++ " -Wl,--export-dynamic" end return fl end diff --git a/doc/src/manual/strings.md b/doc/src/manual/strings.md index a1298af12de5b..f64631fddec46 100644 --- a/doc/src/manual/strings.md +++ b/doc/src/manual/strings.md @@ -332,29 +332,16 @@ julia> string(greet, ", ", whom, ".\n") "Hello, world.\n" ``` -Julia also provides `*` for string concatenation: +Julia also provides `++` for string concatenation: ```jldoctest stringconcat -julia> greet * ", " * whom * ".\n" +julia> greet ++ ", " ++ whom ++ ".\n" "Hello, world.\n" ``` -While `*` may seem like a surprising choice to users of languages that provide `+` for string -concatenation, this use of `*` has precedent in mathematics, particularly in abstract algebra. - -In mathematics, `+` usually denotes a *commutative* operation, where the order of the operands does -not matter. An example of this is matrix addition, where `A + B == B + A` for any matrices `A` and `B` -that have the same shape. In contrast, `*` typically denotes a *noncommutative* operation, where the -order of the operands *does* matter. An example of this is matrix multiplication, where in general -`A * B != B * A`. As with matrix multiplication, string concatenation is noncommutative: -`greet * whom != whom * greet`. As such, `*` is a more natural choice for an infix string concatenation -operator, consistent with common mathematical use. - -More precisely, the set of all finite-length strings *S* together with the string concatenation operator -`*` forms a [free monoid](https://en.wikipedia.org/wiki/Free_monoid) (*S*, `*`). The identity element -of this set is the empty string, `""`. Whenever a free monoid is not commutative, the operation is -typically represented as `\cdot`, `*`, or a similar symbol, rather than `+`, which as stated usually -implies commutativity. +More generally, `++` is a *concatenation* operator that can concatenate +strings, arrays and elements thereof (for which it calls [`vcat`](@ref)), +and other types. ## [Interpolation](@id string-interpolation) diff --git a/examples/typetree.jl b/examples/typetree.jl index 1ca8714833291..f1e7a192be825 100644 --- a/examples/typetree.jl +++ b/examples/typetree.jl @@ -134,7 +134,7 @@ function print_tree(subtypes::Dict{Binding, TTNode}, pfx::String="") println(pfx, "+- ", n, " = ", v.typ, " ", type_props(v.typ)) end v.typ === Function && println(pfx, ". ## hiding implicit Function subtypes ##") - print_tree(v.subtypes, pfx * ". ") + print_tree(v.subtypes, pfx ++ ". ") end end diff --git a/src/julia-parser.scm b/src/julia-parser.scm index e15e23d7fb016..6a18a2bb616b7 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -19,9 +19,10 @@ (append! '(|<:| |>:| in isa) (add-dots '(> < >= ≥ <= ≤ == === ≡ != ≠ !== ≢ ∈ ∉ ∋ ∌ ⊆ ⊈ ⊂ ⊄ ⊊ ∝ ∊ ∍ ∥ ∦ ∷ ∺ ∻ ∽ ∾ ≁ ≃ ≄ ≅ ≆ ≇ ≈ ≉ ≊ ≋ ≌ ≍ ≎ ≐ ≑ ≒ ≓ ≔ ≕ ≖ ≗ ≘ ≙ ≚ ≛ ≜ ≝ ≞ ≟ ≣ ≦ ≧ ≨ ≩ ≪ ≫ ≬ ≭ ≮ ≯ ≰ ≱ ≲ ≳ ≴ ≵ ≶ ≷ ≸ ≹ ≺ ≻ ≼ ≽ ≾ ≿ ⊀ ⊁ ⊃ ⊅ ⊇ ⊉ ⊋ ⊏ ⊐ ⊑ ⊒ ⊜ ⊩ ⊬ ⊮ ⊰ ⊱ ⊲ ⊳ ⊴ ⊵ ⊶ ⊷ ⋍ ⋐ ⋑ ⋕ ⋖ ⋗ ⋘ ⋙ ⋚ ⋛ ⋜ ⋝ ⋞ ⋟ ⋠ ⋡ ⋢ ⋣ ⋤ ⋥ ⋦ ⋧ ⋨ ⋩ ⋪ ⋫ ⋬ ⋭ ⋲ ⋳ ⋴ ⋵ ⋶ ⋷ ⋸ ⋹ ⋺ ⋻ ⋼ ⋽ ⋾ ⋿ ⟈ ⟉ ⟒ ⦷ ⧀ ⧁ ⧡ ⧣ ⧤ ⧥ ⩦ ⩧ ⩪ ⩫ ⩬ ⩭ ⩮ ⩯ ⩰ ⩱ ⩲ ⩳ ⩴ ⩵ ⩶ ⩷ ⩸ ⩹ ⩺ ⩻ ⩼ ⩽ ⩾ ⩿ ⪀ ⪁ ⪂ ⪃ ⪄ ⪅ ⪆ ⪇ ⪈ ⪉ ⪊ ⪋ ⪌ ⪍ ⪎ ⪏ ⪐ ⪑ ⪒ ⪓ ⪔ ⪕ ⪖ ⪗ ⪘ ⪙ ⪚ ⪛ ⪜ ⪝ ⪞ ⪟ ⪠ ⪡ ⪢ ⪣ ⪤ ⪥ ⪦ ⪧ ⪨ ⪩ ⪪ ⪫ ⪬ ⪭ ⪮ ⪯ ⪰ ⪱ ⪲ ⪳ ⪴ ⪵ ⪶ ⪷ ⪸ ⪹ ⪺ ⪻ ⪼ ⪽ ⪾ ⪿ ⫀ ⫁ ⫂ ⫃ ⫄ ⫅ ⫆ ⫇ ⫈ ⫉ ⫊ ⫋ ⫌ ⫍ ⫎ ⫏ ⫐ ⫑ ⫒ ⫓ ⫔ ⫕ ⫖ ⫗ ⫘ ⫙ ⫷ ⫸ ⫹ ⫺ ⊢ ⊣)))) (define prec-pipe (add-dots '(|\|>| |<\||))) +(define prec-concat (add-dots '(|++|))) (define prec-colon '(: |..|)) (define prec-plus (append! '($) - (add-dots '(+ - |\|| ⊕ ⊖ ⊞ ⊟ |++| ∪ ∨ ⊔ ± ∓ ∔ ∸ ≂ ≏ ⊎ ⊻ ⊽ ⋎ ⋓ ⧺ ⧻ ⨈ ⨢ ⨣ ⨤ ⨥ ⨦ ⨧ ⨨ ⨩ ⨪ ⨫ ⨬ ⨭ ⨮ ⨹ ⨺ ⩁ ⩂ ⩅ ⩊ ⩌ ⩏ ⩐ ⩒ ⩔ ⩖ ⩗ ⩛ ⩝ ⩡ ⩢ ⩣)))) + (add-dots '(+ - |\|| ⊕ ⊖ ⊞ ⊟ ∪ ∨ ⊔ ± ∓ ∔ ∸ ≂ ≏ ⊎ ⊻ ⊽ ⋎ ⋓ ⧺ ⧻ ⨈ ⨢ ⨣ ⨤ ⨥ ⨦ ⨧ ⨨ ⨩ ⨪ ⨫ ⨬ ⨭ ⨮ ⨹ ⨺ ⩁ ⩂ ⩅ ⩊ ⩌ ⩏ ⩐ ⩒ ⩔ ⩖ ⩗ ⩛ ⩝ ⩡ ⩢ ⩣)))) (define prec-bitshift (add-dots '(<< >> >>>))) (define prec-times (add-dots '(* / ÷ % & ⋅ ∘ × |\\| ∩ ∧ ⊗ ⊘ ⊙ ⊚ ⊛ ⊠ ⊡ ⊓ ∗ ∙ ∤ ⅋ ≀ ⊼ ⋄ ⋆ ⋇ ⋉ ⋊ ⋋ ⋌ ⋏ ⋒ ⟑ ⦸ ⦼ ⦾ ⦿ ⧶ ⧷ ⨇ ⨰ ⨱ ⨲ ⨳ ⨴ ⨵ ⨶ ⨷ ⨸ ⨻ ⨼ ⨽ ⩀ ⩃ ⩄ ⩋ ⩍ ⩎ ⩑ ⩓ ⩕ ⩘ ⩚ ⩜ ⩞ ⩟ ⩠ ⫛ ⊍ ▷ ⨝ ⟕ ⟖ ⟗))) (define prec-rational (add-dots '(//))) @@ -34,7 +35,7 @@ (define prec-names '(prec-assignment prec-conditional prec-lazy-or prec-lazy-and prec-arrow prec-comparison - prec-pipe prec-colon prec-plus prec-bitshift prec-times prec-rational + prec-pipe prec-concat prec-colon prec-plus prec-bitshift prec-times prec-rational prec-power prec-decl prec-dot)) (define (Set l) @@ -759,7 +760,8 @@ `(call ,op ,arg1 ,arg2)))) (else ex))))) -(define (parse-pipes s) (parse-LtoR s parse-range is-prec-pipe?)) +(define (parse-pipes s) (parse-LtoR s parse-concat is-prec-pipe?)) +(define (parse-concat s) (parse-with-chains s parse-range is-prec-concat? '++)) ; parse ranges and postfix ... ; colon is strange; 3 arguments with 2 colons yields one call: @@ -828,7 +830,7 @@ ;; parse left to right, combining chains of a certain operator into 1 call ;; e.g. a+b+c => (call + a b c) -(define (parse-with-chains s down ops chain-ops) +(define (parse-with-chains s down ops chain-op) (let loop ((ex (down s))) (let ((t (peek-token s))) (if (not (ops t)) @@ -840,15 +842,15 @@ ;; here we have "x -y" (ts:put-back! s t) ex) - ((memq t chain-ops) + ((eq? t chain-op) (loop (list* 'call t ex (parse-chain s down t)))) (else (loop (list 'call t ex (down s)))))))))) -(define (parse-expr s) (parse-with-chains s parse-shift is-prec-plus? '(+ ++))) +(define (parse-expr s) (parse-with-chains s parse-shift is-prec-plus? '+)) (define (parse-shift s) (parse-LtoR s parse-term is-prec-bitshift?)) -(define (parse-term s) (parse-with-chains s parse-rational is-prec-times? '(*))) +(define (parse-term s) (parse-with-chains s parse-rational is-prec-times? '*)) (define (parse-rational s) (parse-LtoR s parse-unary-subtype is-prec-rational?)) ;; parse `<: A where B` as `<: (A where B)` (issue #21545) diff --git a/test/channels.jl b/test/channels.jl index 7f5d206f99e70..4e21ab0554e61 100644 --- a/test/channels.jl +++ b/test/channels.jl @@ -220,7 +220,7 @@ end # test for yield/wait/event failures -@noinline garbage_finalizer(f) = finalizer("gar" * "bage", f) +@noinline garbage_finalizer(f) = finalizer("gar" ++ "bage", f) let t, run = Ref(0) gc_enable(false) # test for finalizers trying to yield leading to failed attempts to context switch diff --git a/test/choosetests.jl b/test/choosetests.jl index b44474f0b2751..48ac08670e1d4 100644 --- a/test/choosetests.jl +++ b/test/choosetests.jl @@ -153,7 +153,7 @@ function choosetests(choices = []) try ipa = getipaddr() catch - warn("Networking unavailable: Skipping tests [" * join(net_required_for, ", ") * "]") + warn("Networking unavailable: Skipping tests [" ++ join(net_required_for, ", ") ++ "]") net_on = false end diff --git a/test/dates/io.jl b/test/dates/io.jl index 4a34d87859637..3e1c214d73901 100644 --- a/test/dates/io.jl +++ b/test/dates/io.jl @@ -144,15 +144,15 @@ f2 = "1996 1 1" j = "1996-01-15" f = "yyyy-mm-dd zzz" @test Dates.DateTime(j, f) == dt -@test Dates.format(dt, f) == j * " zzz" +@test Dates.format(dt, f) == j ++ " zzz" k = "1996-01-15 10:00:00" f = "yyyy-mm-dd HH:MM:SS zzz" @test Dates.DateTime(k, f) == dt + Dates.Hour(10) -@test Dates.format(dt + Dates.Hour(10), f) == k * " zzz" +@test Dates.format(dt + Dates.Hour(10), f) == k ++ " zzz" l = "1996-01-15 10:10:10.25" f = "yyyy-mm-dd HH:MM:SS.ss zzz" @test Dates.DateTime(l, f) == dt + Dates.Hour(10) + Dates.Minute(10) + Dates.Second(10) + Dates.Millisecond(250) -@test Dates.format(dt + Dates.Hour(10) + Dates.Minute(10) + Dates.Second(10) + Dates.Millisecond(250), f) == l * " zzz" +@test Dates.format(dt + Dates.Hour(10) + Dates.Minute(10) + Dates.Second(10) + Dates.Millisecond(250), f) == l ++ " zzz" r = "1/15/1996" # Excel f = "m/dd/yyyy" @@ -169,7 +169,7 @@ f = "yyyy-mm-dd HH:MM:SS" w = "1996-01-15T10:00:00" f = "yyyy-mm-ddTHH:MM:SS zzz" @test Dates.DateTime(w, f) == dt + Dates.Hour(10) -@test Dates.format(dt + Dates.Hour(10), f) == w * " zzz" +@test Dates.format(dt + Dates.Hour(10), f) == w ++ " zzz" f = "yyyy/m" y = "1996/1" @@ -443,7 +443,7 @@ end @test_throws InexactError Dates.parse_components(".1234", Dates.DateFormat(".s")) # Ensure that no overflow occurs when using Int32 literals: Int32(10)^10 - @test Dates.parse_components("." * rpad(999, 10, '0'), Dates.DateFormat(".s")) == [Dates.Millisecond(999)] + @test Dates.parse_components("." ++ rpad(999, 10, '0'), Dates.DateFormat(".s")) == [Dates.Millisecond(999)] end # Time Parsing diff --git a/test/dates/periods.jl b/test/dates/periods.jl index f8c068e39e032..307fa2fe4ebfb 100644 --- a/test/dates/periods.jl +++ b/test/dates/periods.jl @@ -247,7 +247,7 @@ let Dates.value(b::Beat) = b.value Dates.toms(b::Beat) = Dates.value(b) * 86400 - Dates._units(b::Beat) = " beat" * (abs(Dates.value(b)) == 1 ? "" : "s") + Dates._units(b::Beat) = " beat" ++ (abs(Dates.value(b)) == 1 ? "" : "s") Base.promote_rule(::Type{Dates.Day}, ::Type{Beat}) = Dates.Millisecond Base.convert{T<:Dates.Millisecond}(::Type{T}, b::Beat) = T(Dates.toms(b)) diff --git a/test/distributed_exec.jl b/test/distributed_exec.jl index 402948cf96ec4..a6a21d447e3db 100644 --- a/test/distributed_exec.jl +++ b/test/distributed_exec.jl @@ -273,11 +273,11 @@ dims = (20,20,20) if is_linux() S = SharedArray{Int64,3}(dims) @test startswith(S.segname, "/jl") - @test !ispath("/dev/shm" * S.segname) + @test !ispath("/dev/shm" ++ S.segname) S = SharedArray{Int64,3}(dims; pids=[id_other]) @test startswith(S.segname, "/jl") - @test !ispath("/dev/shm" * S.segname) + @test !ispath("/dev/shm" ++ S.segname) end # TODO : Need a similar test of shmem cleanup for OSX diff --git a/test/libgit2.jl b/test/libgit2.jl index 8d0065e0b54ff..1c876be2db4c1 100644 --- a/test/libgit2.jl +++ b/test/libgit2.jl @@ -1479,7 +1479,7 @@ mktempdir() do dir #= # Explicitly setting these env variables to an existing but invalid key pair # means the user will be given a prompt with that defaults to the given values. - withenv("SSH_KEY_PATH" => invalid_key, "SSH_PUB_KEY_PATH" => invalid_key * ".pub") do + withenv("SSH_KEY_PATH" => invalid_key, "SSH_PUB_KEY_PATH" => invalid_key ++ ".pub") do challenges = [ "Private key location for 'git@github.com' [$invalid_key]:" => "$valid_key\n", ] @@ -1492,7 +1492,7 @@ mktempdir() do dir # TODO: Tests are currently broken. Credential callback currently infinite loops # and never prompts user to change private keys. #= - withenv("SSH_KEY_PATH" => valid_key, "SSH_PUB_KEY_PATH" => valid_key * ".public") do + withenv("SSH_KEY_PATH" => valid_key, "SSH_PUB_KEY_PATH" => valid_key ++ ".public") do @test !isfile(ENV["SSH_PUB_KEY_PATH"]) # User explicitly sets the SSH_PUB_KEY_PATH incorrectly. @@ -1762,9 +1762,9 @@ mktempdir() do dir end if openssl_installed && !isempty(common_name) mktempdir() do root - key = joinpath(root, common_name * ".key") - cert = joinpath(root, common_name * ".crt") - pem = joinpath(root, common_name * ".pem") + key = joinpath(root, common_name ++ ".key") + cert = joinpath(root, common_name ++ ".crt") + pem = joinpath(root, common_name ++ ".pem") # Generated a certificate which has the CN set correctly but no subjectAltName run(pipeline(`openssl req -new -x509 -newkey rsa:2048 -nodes -keyout $key -out $cert -days 1 -subj "/CN=$common_name"`, stderr=DevNull)) diff --git a/test/numbers.jl b/test/numbers.jl index 8c1d4307a37f1..fb60b798bc01c 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -308,8 +308,8 @@ end @test base(12,typemin(UInt128)) == "0" @test base(12,typemax(UInt128)) == "5916b64b41143526a777873841863a6a6993" -@test bin(typemin(Int8)) == "-1"*"0"^7 -@test bin(typemax(Int8)) == "1"^7 +@test bin(typemin(Int8)) == "-1"++repeat("0",7) +@test bin(typemax(Int8)) == repeat("1",7) @test oct(typemin(Int8)) == "-200" @test oct(typemax(Int8)) == "177" @test dec(typemin(Int8)) == "-128" @@ -323,8 +323,8 @@ end @test base(12,typemin(Int8)) == "-a8" @test base(12,typemax(Int8)) == "a7" -@test bin(typemin(Int16)) == "-1"*"0"^15 -@test bin(typemax(Int16)) == "1"^15 +@test bin(typemin(Int16)) == "-1"++repeat("0",15) +@test bin(typemax(Int16)) == repeat("1",15) @test oct(typemin(Int16)) == "-100000" @test oct(typemax(Int16)) == "77777" @test dec(typemin(Int16)) == "-32768" @@ -338,7 +338,7 @@ end @test base(12,typemin(Int16)) == "-16b68" @test base(12,typemax(Int16)) == "16b67" -@test bin(typemin(Int32)) == "-1"*"0"^31 +@test bin(typemin(Int32)) == "-1"++repeat("0",31) @test bin(typemax(Int32)) == "1"^31 @test oct(typemin(Int32)) == "-20000000000" @test oct(typemax(Int32)) == "17777777777" @@ -353,8 +353,8 @@ end @test base(12,typemin(Int32)) == "-4bb2308a8" @test base(12,typemax(Int32)) == "4bb2308a7" -@test bin(typemin(Int64)) == "-1"*"0"^63 -@test bin(typemax(Int64)) == "1"^63 +@test bin(typemin(Int64)) == "-1"++repeat("0",63) +@test bin(typemax(Int64)) == repeat("1",63) @test oct(typemin(Int64)) == "-1000000000000000000000" @test oct(typemax(Int64)) == "777777777777777777777" @test dec(typemin(Int64)) == "-9223372036854775808" @@ -368,8 +368,8 @@ end @test base(12,typemin(Int64)) == "-41a792678515120368" @test base(12,typemax(Int64)) == "41a792678515120367" -@test bin(typemin(Int128)) == "-1"*"0"^127 -@test bin(typemax(Int128)) == "1"^127 +@test bin(typemin(Int128)) == "-1"++repeat("0",127) +@test bin(typemax(Int128)) == repeat("1",127) @test oct(typemin(Int128)) == "-2000000000000000000000000000000000000000000" @test oct(typemax(Int128)) == "1777777777777777777777777777777777777777777" @test hex(typemin(Int128)) == "-80000000000000000000000000000000" diff --git a/test/pkg.jl b/test/pkg.jl index abd04ea9d59f7..661aa1b4a8940 100644 --- a/test/pkg.jl +++ b/test/pkg.jl @@ -202,8 +202,8 @@ temp_pkg_dir() do error("unexpected") catch err @test isa(err.exceptions[1].ex, PkgError) - @test err.exceptions[1].ex.msg == "REPL can't be installed because " * - "it has no versions that support $VERSION of julia. You may " * + @test err.exceptions[1].ex.msg == "REPL can't be installed because " ++ + "it has no versions that support $VERSION of julia. You may " ++ "need to update METADATA by running `Pkg.update()`" end diff --git a/test/replcompletions.jl b/test/replcompletions.jl index 6e0d9a38ebda3..96fbf77ac6fd3 100644 --- a/test/replcompletions.jl +++ b/test/replcompletions.jl @@ -616,7 +616,7 @@ end let #test that it can auto complete with spaces in file/path path = tempdir() - space_folder = randstring() * " α" + space_folder = randstring() ++ " α" dir = joinpath(path, space_folder) dir_space = replace(space_folder, " ", "\\ ") mkdir(dir) @@ -654,7 +654,7 @@ if is_windows() s = "cd ..\\\\" c,r = test_scomplete(s) @test r == length(s)+1:length(s) - @test temp_name * "\\\\" in c + @test temp_name ++ "\\\\" in c s = "ls $(file[1:2])" c,r = test_scomplete(s) @@ -664,7 +664,7 @@ if is_windows() s = "cd(\"..\\" c,r = test_complete(s) @test r == length(s)+1:length(s) - @test temp_name * "\\\\" in c + @test temp_name ++ "\\\\" in c s = "cd(\"$(file[1:2])" c,r = test_complete(s) diff --git a/test/runtests.jl b/test/runtests.jl index 262ca6a46ecca..2edf9004088fa 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -70,7 +70,7 @@ cd(dirname(@__FILE__)) do end end if !isa(resp[1], Exception) - print_with_color(:white, rpad(test*" ($wrkr)", name_align, " "), " | ") + print_with_color(:white, rpad(test++" ($wrkr)", name_align, " "), " | ") time_str = @sprintf("%7.2f",resp[2]) print_with_color(:white, rpad(time_str,elapsed_align," "), " | ") gc_str = @sprintf("%5.2f",resp[5].total_time/10^9) diff --git a/test/show.jl b/test/show.jl index 2c205c478a7a3..5e58a55812ebd 100644 --- a/test/show.jl +++ b/test/show.jl @@ -289,7 +289,7 @@ end" # issue #9474 for s in ("(1::Int64 == 1::Int64)::Bool", "(1:2:3) + 4", "x = 1:2:3") - @test sprint(show, parse(s)) == ":("*s*")" + @test sprint(show, parse(s)) == ":("++s++")" end # parametric type instantiation printing @@ -778,4 +778,4 @@ let fname = tempname() finally rm(fname, force=true) end -end \ No newline at end of file +end diff --git a/test/socket.jl b/test/socket.jl index 917d3c240a13c..1e6c8464133c0 100644 --- a/test/socket.jl +++ b/test/socket.jl @@ -89,12 +89,12 @@ for testport in [0, defaultport] close(sock) end wait(port) - @test readstring(connect(fetch(port))) == "Hello World\n" * ("a1\n"^100) + @test readstring(connect(fetch(port))) == "Hello World\n" ++ repeat("a1\n",100) wait(tsk) end mktempdir() do tmpdir - socketname = is_windows() ? ("\\\\.\\pipe\\uv-test-" * randstring(6)) : joinpath(tmpdir, "socket") + socketname = is_windows() ? ("\\\\.\\pipe\\uv-test-" ++ randstring(6)) : joinpath(tmpdir, "socket") c = Base.Condition() tsk = @async begin s = listen(socketname) @@ -329,4 +329,3 @@ let @test test_connect(addr) end - diff --git a/test/strings/basic.jl b/test/strings/basic.jl index bf1fb7741c862..69dfc8648e8bd 100644 --- a/test/strings/basic.jl +++ b/test/strings/basic.jl @@ -409,13 +409,9 @@ foobaz(ch) = reinterpret(Char, typemax(UInt32)) @test map(foobar, GenericString(str)) == String(repeat(b"\ud800", outer=[17])) @test map(foobaz, GenericString(str)) == String(repeat(b"\ufffd", outer=[17])) -@test "a".*["b","c"] == ["ab","ac"] -@test ["b","c"].*"a" == ["ba","ca"] -@test ["a","b"].*["c" "d"] == ["ac" "ad"; "bc" "bd"] - -@test one(String) == "" -@test prod(["*" for i in 1:3]) == "***" -@test prod(["*" for i in 1:0]) == "" +@test "a".++["b","c"] == ["ab","ac"] +@test ["b","c"].++"a" == ["ba","ca"] +@test ["a","b"].++["c" "d"] == ["ac" "ad"; "bc" "bd"] # Make sure NULL pointers are handled consistently by String @test_throws ArgumentError unsafe_string(Ptr{UInt8}(0)) diff --git a/test/strings/types.jl b/test/strings/types.jl index c4ff5227a02e2..4d869796c9dda 100644 --- a/test/strings/types.jl +++ b/test/strings/types.jl @@ -4,7 +4,7 @@ ## SubString tests ## u8str = "∀ ε > 0, ∃ δ > 0: |x-y| < δ ⇒ |f(x)-f(y)| < ε" -u8str2 = u8str^2 +u8str2 = repeat(u8str,2) len_u8str = length(u8str) slen_u8str = length(u8str) len_u8str2 = length(u8str2) diff --git a/test/unicode/utf8proc.jl b/test/unicode/utf8proc.jl index 403c2775f9897..b88335ca34af0 100644 --- a/test/unicode/utf8proc.jl +++ b/test/unicode/utf8proc.jl @@ -6,8 +6,8 @@ @test "\u006e\u0303" == normalize_string("\u00f1", :NFD) @test normalize_string("\ufb00", :NFC) != "ff" @test normalize_string("\ufb00", :NFKC) == "ff" - @test normalize_string("\u006e\u0303\ufb00", :NFKC) == "\u00f1"*"ff" - @test normalize_string("\u00f1\ufb00", :NFKD) == "\u006e\u0303"*"ff" + @test normalize_string("\u006e\u0303\ufb00", :NFKC) == "\u00f1"++"ff" + @test normalize_string("\u00f1\ufb00", :NFKD) == "\u006e\u0303"++"ff" @test normalize_string("\u006e\u0303", compose=true) == "\u00f1" @test "\u006e\u0303" == normalize_string("\u00f1", decompose=true) @test normalize_string("\u006e\u0303\u00b5",compat=true) == "\u00f1\u03bc" From 28d3c31d871e2444ffd7de1e8d3422e1b638344b Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Wed, 21 Jun 2017 15:11:03 -0400 Subject: [PATCH 2/2] more ++ fixes --- base/dates/periods.jl | 2 +- base/markdown/GitHub/GitHub.jl | 4 ++-- base/markdown/parse/util.jl | 7 ++++--- base/strings/io.jl | 3 +++ doc/src/manual/mathematical-operations.md | 2 +- doc/src/manual/metaprogramming.md | 6 +++--- doc/src/stdlib/arrays.md | 1 + doc/src/stdlib/strings.md | 3 +-- 8 files changed, 16 insertions(+), 12 deletions(-) diff --git a/base/dates/periods.jl b/base/dates/periods.jl index 817ededa8fc64..0af19a467ede4 100644 --- a/base/dates/periods.jl +++ b/base/dates/periods.jl @@ -334,7 +334,7 @@ function Base.string(x::CompoundPeriod) else s = "" for p in x.periods - s *= ", " ++ string(p) + s = string(s, ", ", p) end return s[3:end] end diff --git a/base/markdown/GitHub/GitHub.jl b/base/markdown/GitHub/GitHub.jl index ae2cfd1120f3a..4813c6b10410d 100644 --- a/base/markdown/GitHub/GitHub.jl +++ b/base/markdown/GitHub/GitHub.jl @@ -16,9 +16,10 @@ function fencedcode(stream::IO, block::MD) ch in flavor && return false buffer = IOBuffer() + chn = repeat(string(ch),n) while !eof(stream) line_start = position(stream) - if startswith(stream, string(ch) ^ n) + if startswith(stream, chn) if !startswith(stream, string(ch)) if flavor == "math" push!(block, LaTeX(String(take!(buffer)) |> chomp)) @@ -63,4 +64,3 @@ end linebreak, escapes, en_dash, inline_code, asterisk_bold, asterisk_italic, image, footnote_link, link, autolink] - diff --git a/base/markdown/parse/util.jl b/base/markdown/parse/util.jl index 38f1a38da6000..1ddf388dc31a4 100644 --- a/base/markdown/parse/util.jl +++ b/base/markdown/parse/util.jl @@ -179,20 +179,21 @@ function parse_inline_wrapper(stream::IO, delimiter::AbstractString; rep = false (read(stream, Char) in delimiter) && return nothing end n = nmin - startswith(stream, delimiter^n) || return nothing + startswith(stream, repeat(delimiter,n)) || return nothing while startswith(stream, delimiter); n += 1; end !rep && n > nmin && return nothing !eof(stream) && Char(peek(stream)) in whitespace && return nothing buffer = IOBuffer() + delimitern = repeat(delimiter,n) while !eof(stream) char = read(stream, Char) write(buffer, char) - if !(char in whitespace || char == '\n' || char in delimiter) && startswith(stream, delimiter^n) + if !(char in whitespace || char == '\n' || char in delimiter) && startswith(stream, delimitern) trailing = 0 while startswith(stream, delimiter); trailing += 1; end trailing == 0 && return String(take!(buffer)) - write(buffer, delimiter ^ (n + trailing)) + write(buffer, repeat(delimiter, n + trailing)) end end end diff --git a/base/strings/io.jl b/base/strings/io.jl index 89ae79301de14..710a37620e9e8 100644 --- a/base/strings/io.jl +++ b/base/strings/io.jl @@ -112,6 +112,9 @@ string_with_env(env, xs...) = print_to_string(xs...; env=env) Create a string from any values using the [`print`](@ref) function. +The [`++`](@ref) concatenation operator is equivalent to a call to `string` +when applied to one or more string arguments. + ```jldoctest julia> string("a", 1, true) "a1true" diff --git a/doc/src/manual/mathematical-operations.md b/doc/src/manual/mathematical-operations.md index a6ff8bdea53f8..a8f617e3adaeb 100644 --- a/doc/src/manual/mathematical-operations.md +++ b/doc/src/manual/mathematical-operations.md @@ -366,7 +366,7 @@ You can also find the numerical precedence for any given operator via the built- ```jldoctest julia> Base.operator_precedence(:+), Base.operator_precedence(:*), Base.operator_precedence(:.) -(9, 11, 15) +(10, 12, 16) julia> Base.operator_precedence(:+=), Base.operator_precedence(:(=)) # (Note the necessary parens on `:(=)`) (1, 1) diff --git a/doc/src/manual/metaprogramming.md b/doc/src/manual/metaprogramming.md index 031f93fdacf52..e17723092ed94 100644 --- a/doc/src/manual/metaprogramming.md +++ b/doc/src/manual/metaprogramming.md @@ -965,11 +965,11 @@ Int64 julia> x # now we print x 4 -julia> y = foo("bar"); -String +julia> y = foo(3.0); +Float64 julia> y -"barbar" +9.0 ``` So, we see that in the body of the generated function, `x` is the *type* of the passed argument, diff --git a/doc/src/stdlib/arrays.md b/doc/src/stdlib/arrays.md index 9221735386c58..5968161dcd320 100644 --- a/doc/src/stdlib/arrays.md +++ b/doc/src/stdlib/arrays.md @@ -94,6 +94,7 @@ Base.cat Base.vcat Base.hcat Base.hvcat +Base.:++ Base.flipdim Base.circshift Base.circshift! diff --git a/doc/src/stdlib/strings.md b/doc/src/stdlib/strings.md index c04edc20566cb..15588a86ae28b 100644 --- a/doc/src/stdlib/strings.md +++ b/doc/src/stdlib/strings.md @@ -3,9 +3,8 @@ ```@docs Base.length(::AbstractString) Base.sizeof(::AbstractString) -Base.:*(::AbstractString, ::Any...) -Base.:^(::AbstractString, ::Integer) Base.string +Base.repeat(::AbstractString, ::Integer) Base.repr Core.String(::AbstractString) Base.transcode