From fa62910597c2303b779dc7d976f68d64c86cad0a Mon Sep 17 00:00:00 2001 From: Fengyang Wang Date: Thu, 19 Jan 2017 16:44:30 -0500 Subject: [PATCH 1/4] Migrate from DataType to Type everywhere --- src/curly.jl | 14 +++++++------- src/dynamic.jl | 8 ++++---- src/functions.jl | 22 +++++++++++----------- src/guesstype.jl | 31 ++++++++++--------------------- src/knownsyms.jl | 4 ++-- src/linttypes.jl | 4 ++-- src/ref.jl | 4 ++-- src/types.jl | 2 +- src/variables.jl | 20 ++++++++++---------- 9 files changed, 49 insertions(+), 60 deletions(-) diff --git a/src/curly.jl b/src/curly.jl index 2efa474..3084dc7 100644 --- a/src/curly.jl +++ b/src/curly.jl @@ -6,13 +6,13 @@ # contracts for common collections / type parametrized types # TODO: Can we be more specific here? What about detecting contract? const CURLY_CONTRACTS = Dict{Symbol, Any}( - :Array => (DataType, Integer), - :Dict => (DataType, DataType), - :Matrix => (DataType,), - :Set => (DataType,), - :Type => (DataType,), + :Array => (Type, Integer), + :Dict => (Type, Type), + :Matrix => (Type,), + :Set => (Type,), + :Type => (Type,), :Val => (Any,), - :Vector => (DataType,)) + :Vector => (Type,)) function lintcurly(ex::Expr, ctx::LintContext) head = ex.args[1] @@ -28,7 +28,7 @@ function lintcurly(ex::Expr, ctx::LintContext) continue # grandfathered else t = guesstype(a, ctx) - if !(t == DataType || t == Symbol || isbits(t) || t == Any) + if !(t <: Type || t == Symbol || isbits(t) || t == Any) msg(ctx, :W441, a, "probably illegal use inside curly") elseif contract != nothing if i - 1 > length(contract) diff --git a/src/dynamic.jl b/src/dynamic.jl index ccc9a0c..414901d 100644 --- a/src/dynamic.jl +++ b/src/dynamic.jl @@ -1,14 +1,14 @@ """ -Determine the type of suspected imported binding `sym`. Return `:DataType` if -it is a likely type, `:var` if it likely exists but is likely not a type, and -`:Any` if it cannot be located, which may indicate. +Determine the type of suspected imported binding `sym`. Return `:Type` if it is +a likely type, `:var` if it likely exists but is likely not a type, and `:Any` +if it cannot be located, which may indicate. """ function dynamic_imported_binding_type(sym) if isdefined(Main, sym) if isupper(string(sym)[1]) try if isa(eval(Main, sym), Type) - return :DataType + return :Type end end end diff --git a/src/functions.jl b/src/functions.jl index 50a873e..e56f0bc 100644 --- a/src/functions.jl +++ b/src/functions.jl @@ -1,6 +1,6 @@ -const commoncollections = DataType[ +const commoncollections = [ Array, AbstractArray, BitArray, Set, Associative] -const commoncollmethods = Dict{Symbol, Set{DataType}}() +const commoncollmethods = Dict{Symbol, Set{Type}}() # deprecation of specialized version of constructors const deprecated_constructors = @@ -39,7 +39,7 @@ function initcommoncollfuncs() end s = Symbol(mtch.match) if !haskey(commoncollmethods, s) - commoncollmethods[s] = Set{DataType}() + commoncollmethods[s] = Set{Type}() end push!(commoncollmethods[s], t) end @@ -51,7 +51,7 @@ function initcommoncollfuncs() end end # ADD COMMON FUNCTIONS WITH EASILY-MISTAKEN SIGNATURES HERE - commoncollmethods[:(append!)] = Set{DataType}() + commoncollmethods[:(append!)] = Set{Type}() end function lintfuncargtype(ex, ctx::LintContext) @@ -123,7 +123,7 @@ function lintfunction(ex::Expr, ctx::LintContext; ctorType = Symbol(""), isstage end if in(typeconstraint, knowntypes) dt = eval(typeconstraint) - if typeof(dt) == DataType && isleaftype(dt) + if isa(dt, Type) && isleaftype(dt) msg(ctx, :E513, adt, "leaf type as a type constraint makes no sense") end end @@ -171,7 +171,7 @@ function lintfunction(ex::Expr, ctx::LintContext; ctorType = Symbol(""), isstage push!(argsSeen, sube) stacktop.localarguments[end][sube] = VarInfo(ctx.line) if isstaged - assertions[sube] = DataType + assertions[sube] = Type end return sube elseif sube.head == :parameters @@ -184,7 +184,7 @@ function lintfunction(ex::Expr, ctx::LintContext; ctorType = Symbol(""), isstage sym = resolveArguments(kw, 0) if typeof(sym)== Symbol if isstaged - assertions[sym] = DataType + assertions[sym] = Type else # This may change to Array{(Symbol,Any), 1} in the future assertions[sym] = Array{Any,1} @@ -236,7 +236,7 @@ function lintfunction(ex::Expr, ctx::LintContext; ctorType = Symbol(""), isstage sym = resolveArguments(sube.args[1], 0) if typeof(sym) == Symbol if isstaged - assertions[sym] = Tuple{Vararg{DataType}} + assertions[sym] = Tuple{Vararg{Type}} elseif haskey(assertions, sym) assertions[sym] = Tuple{Vararg{assertions[sym]}} else @@ -268,7 +268,7 @@ function lintfunction(ex::Expr, ctx::LintContext; ctorType = Symbol(""), isstage vi = stacktop.localarguments[end][s] if haskey(assertions, s) dt = eval(assertions[s]) - if typeof(dt) == DataType || typeof(dt) == (DataType,) + if isa(dt, Type) vi.typeactual = dt if dt != Any && haskey(typeRHShints, s) && typeRHShints[s] != Any && !(typeRHShints[s] <: dt) @@ -292,7 +292,7 @@ function lintfunction(ex::Expr, ctx::LintContext; ctorType = Symbol(""), isstage end if ctorType != Symbol("") && fname == ctorType t = guesstype(ex.args[2], ctx) - if typeof(t) == DataType + if isa(t, Type) if t.name.name != ctorType msg(ctx, :E611, "constructor doesn't seem to return the constructed object") end @@ -519,7 +519,7 @@ function lintfunctioncall(ex::Expr, ctx::LintContext; inthrow::Bool=false) if contains(s,"error") || contains(s,"exception") || contains(s,"mismatch") || contains(s,"fault") try dt = eval(ex.args[1]) - if typeof(dt) == DataType && dt <: Exception && !pragmaexists( "Ignore unthrown " * string(ex.args[1]), ctx) + if isa(dt, Type) && dt <: Exception && !pragmaexists( "Ignore unthrown " * string(ex.args[1]), ctx) msg(ctx, :W448, string(ex.args[1]) * " is an Exception but it is not enclosed in a throw()") end end diff --git a/src/guesstype.jl b/src/guesstype.jl index b6b3389..78978a5 100644 --- a/src/guesstype.jl +++ b/src/guesstype.jl @@ -24,7 +24,7 @@ function evaltype(ex) try ret = eval(Main, ex) end - return isa(ret, DataType) ? ret : Any + return isa(ret, Type) ? ret : Any end # ex should be a type. figure out what it is @@ -93,14 +93,14 @@ function guesstype(ex, ctx::LintContext) end # TODO: this should be a module function checkret = x -> begin - if typeof(x) == DataType || typeof(x) == (DataType,) + if isa(x, Type) return x else tmp = x try tmp = eval(x) end - if typeof(tmp) == DataType || typeof(tmp) == (DataType,) + if isa(tmp, Type) return tmp else return x @@ -123,7 +123,7 @@ function guesstype(ex, ctx::LintContext) end for i in length(ctx.callstack):-1:1 if in(sym, ctx.callstack[i].types) - return DataType + return Type end if in(sym, ctx.callstack[i].functions) return Function @@ -166,7 +166,7 @@ function guesstype(ex, ctx::LintContext) return evaltype(ex.args[2]) end - # this is hackish because the return type is a Symbol, not a DataType + # this is hackish because the return type is a Symbol, not a Type if isexpr(ex, :call) && ex.args[1] == :new return Symbol(ctx.scope) end @@ -242,7 +242,7 @@ function guesstype(ex, ctx::LintContext) end if isexpr(ex, :curly) - return DataType + return Type end if isexpr(ex, :call) && isexpr(ex.args[1], :curly) @@ -288,7 +288,7 @@ function guesstype(ex, ctx::LintContext) end elt = evaltype(ex.args[2]) - if length(sig) >= 1 && sig[1] == DataType + if length(sig) >= 1 && sig[1] == Type if length(sig) == 2 && isexpr(ex.args[3], :tuple) return Array{elt, length(ex.args[3].args)} elseif length(sig) == 2 && sig[2] <: Tuple && all(x->x <: Integer, sig[2]) @@ -378,11 +378,11 @@ function guesstype(ex, ctx::LintContext) if typeof(ex.args[1]) == Symbol what = registersymboluse(ex.args[1], ctx, false) - if what == :DataType + if what == :Type elt = parsetype(ex.args[1]) return Array{elt, 1} elseif what == :Any - msg(ctx, :W543, ex.args[1], "Lint cannot determine if DataType or not") + msg(ctx, :W543, ex.args[1], "Lint cannot determine if Type or not") return Any end end @@ -432,17 +432,6 @@ function guesstype(ex, ctx::LintContext) end end return Any - elseif typeof(partyp) == (DataType,) # e.g. (Int,), (Int...,), (DataType,...) - fst = partyp[1] - try - if fst.name.name == :Vararg - return fst.parameters[1] - else - return fst - end - catch - return Any - end elseif partyp <: Associative ktypeexpect = keytype(partyp) vtypeexpect = valuetype(partyp) @@ -476,7 +465,7 @@ function guesstype(ex, ctx::LintContext) return Any end if length(partyp.parameters) == 1 || partyp.parameters[1].name.name == :Vararg - if typeof(partyp.parameters[1].parameters[1]) <: DataType + if typeof(partyp.parameters[1].parameters[1]) <: Type return evaltype(partyp.parameters[1].parameters[1].name.name) end end diff --git a/src/knownsyms.jl b/src/knownsyms.jl index e4e7c61..7ffc509 100644 --- a/src/knownsyms.jl +++ b/src/knownsyms.jl @@ -20,14 +20,14 @@ function cacheknownsyms() union!(knowntypes, filter(names(Base)) do x ok = false try - ok = isa(eval(Base, x), DataType) + ok = isa(eval(Base, x), Type) end ok end) union!(knowntypes, filter(names(Core)) do x ok = false try - ok = isa(eval(Core, x), DataType) + ok = isa(eval(Core, x), Type) end ok end) diff --git a/src/linttypes.jl b/src/linttypes.jl index 525f716..2b65f11 100644 --- a/src/linttypes.jl +++ b/src/linttypes.jl @@ -9,11 +9,11 @@ end type VarInfo line::Int - typeactual::Any # most of the time it's DataType, but could be Tuple of types, too + typeactual::Type typeexpr::Union{Expr, Symbol} # We may know that it is Array{T, 1}, though we do not know T, for example VarInfo() = new(-1, Any, :()) VarInfo(l::Int) = new(l, Any, :()) - VarInfo(l::Int, t::DataType) = new(l, t, :()) + VarInfo(l::Int, t::Type) = new(l, t, :()) VarInfo(l::Int, ex::Expr) = new(l, Any, ex) VarInfo(ex::Expr) = new(-1, Any, ex) end diff --git a/src/ref.jl b/src/ref.jl index 310f85e..343af55 100644 --- a/src/ref.jl +++ b/src/ref.jl @@ -3,11 +3,11 @@ function lintref(ex::Expr, ctx::LintContext) guesstype(ex, ctx) # tickle the type checks on the expression if typeof(sub1)== Symbol # check to see if it's a type - what = registersymboluse(sub1, ctx, false) # :var, :DataType, or :Any + what = registersymboluse(sub1, ctx, false) # :var, :Type, or :Any if what == :Any str = string(sub1) #if !isupper(str[1]) || length(str) <= 2 - msg(ctx, :W544, str, "Lint cannot determine if DataType or not") + msg(ctx, :W544, str, "Lint cannot determine if Type or not") #end end else diff --git a/src/types.jl b/src/types.jl index 4c52ca0..662cb4f 100644 --- a/src/types.jl +++ b/src/types.jl @@ -46,7 +46,7 @@ function linttype(ex::Expr, ctx::LintContext) end if in(typeconstraint, knowntypes) dt = eval(typeconstraint) - if typeof(dt) == DataType && isleaftype(dt) + if isa(dt, Type) && isleaftype(dt) msg(ctx, :E513, adt, "leaf type as a type constraint makes no sense") end end diff --git a/src/variables.jl b/src/variables.jl index 41ea76a..a871435 100644 --- a/src/variables.jl +++ b/src/variables.jl @@ -32,8 +32,8 @@ function pushVarScope(ctx::LintContext) end # returns -# :var - a non-DataType value -# :DataType +# :var - a non-Type value +# :Type # :Any - don't know, could be either (with lint warnings, if strict) # if strict == false, it won't generate lint warnings, just return :Any @@ -47,7 +47,7 @@ function registersymboluse(sym::Symbol, ctx::LintContext, strict::Bool=true) if haskey(stacktop.localvars[i], sym) push!(stacktop.localusedvars[i], sym) # TODO: This is not quite right. We need to check type - # on the sym. If it's DataType, return :DataType + # on the sym. If it's Type, return :Type # if Any, return :Any # otherwise, :var return :var @@ -64,7 +64,7 @@ function registersymboluse(sym::Symbol, ctx::LintContext, strict::Bool=true) # a bunch of whitelist to just grandfather-in if sym in knowntypes - return :DataType + return :Type end if sym in knownsyms return :var @@ -73,7 +73,7 @@ function registersymboluse(sym::Symbol, ctx::LintContext, strict::Bool=true) # Move up call stack, looking at global declarations for i in length(ctx.callstack):-1:1 if in(sym, ctx.callstack[i].types) - return :DataType + return :Type elseif haskey(ctx.callstack[i].declglobs, sym) || in(sym, ctx.callstack[i].functions) || in(sym, ctx.callstack[i].modules) || @@ -132,7 +132,7 @@ function lintlocal(ex::Expr, ctx::LintContext) vi = VarInfo(ctx.line) try dt = eval(Main, sube.args[2]) - if typeof(dt) == DataType + if isa(dt, Type) vi.typeactual = dt else vi.typeexpr = sube.args[2] @@ -213,7 +213,7 @@ function lintassignment(ex::Expr, assign_ops::Symbol, ctx::LintContext; islocal if typeof(s) != Symbol # a.b or a[b] if isexpr(s, [:(.), :ref]) containertype = guesstype(s.args[1], ctx) - if containertype != Any && typeof(containertype) == DataType && !containertype.mutable + if containertype != Any && isa(containertype, Type) && !containertype.mutable msg(ctx, :E525, s.args[1], "is of an immutable type $(containertype)") end end @@ -256,7 +256,7 @@ function lintassignment(ex::Expr, assign_ops::Symbol, ctx::LintContext; islocal try if haskey(assertions, s) dt = eval(Main, assertions[s]) - if typeof(dt) == DataType + if isa(dt, Type) vi.typeactual = dt if !isAnyOrTupleAny(dt) && !isAnyOrTupleAny(rhstype) && !(rhstype <: dt) msg(ctx, :I572, "assert $(s) type= $(dt) but assign a value of " * @@ -283,13 +283,13 @@ function lintassignment(ex::Expr, assign_ops::Symbol, ctx::LintContext; islocal if haskey(ctx.callstack[end].localvars[i], s) found = true prevvi = ctx.callstack[end].localvars[i][s] - if typeof(vi.typeactual) <: DataType && typeof(prevvi.typeactual) <: DataType && + if isa(vi.typeactual, Type) && isa(prevvi.typeactual, Type) && vi.typeactual <: Number && prevvi.typeactual <: Number && assign_ops != :(=) if length(prevvi.typeactual.parameters) == 0 else end continue - elseif typeof(vi.typeactual) <: DataType && typeof(prevvi.typeactual) <: DataType && + elseif isa(vi.typeactual, Type) && isa(prevvi.typeactual, Type) && vi.typeactual <: Number && prevvi.typeactual <: Array && assign_ops != :(=) continue From b4ff632965012816608c5133d2ea41485f253ff8 Mon Sep 17 00:00:00 2001 From: Fengyang Wang Date: Thu, 19 Jan 2017 17:12:38 -0500 Subject: [PATCH 2/4] Rewrite version constraints to be 0.6-friendly --- REQUIRE | 2 +- src/Lint.jl | 3 +++ src/controls.jl | 29 ++++++++++++----------------- src/exprutils.jl | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 18 deletions(-) create mode 100644 src/exprutils.jl diff --git a/REQUIRE b/REQUIRE index 4f65da5..278499a 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,2 +1,2 @@ julia 0.4 -Compat 0.8.2 +Compat 0.11.0 diff --git a/src/Lint.jl b/src/Lint.jl index cc7fbf6..b070cde 100644 --- a/src/Lint.jl +++ b/src/Lint.jl @@ -20,6 +20,9 @@ end import Base: == +include("exprutils.jl") +using .ExpressionUtils + include("linttypes.jl") include("messages.jl") include("knownsyms.jl") diff --git a/src/controls.jl b/src/controls.jl index 59fe167..b939893 100644 --- a/src/controls.jl +++ b/src/controls.jl @@ -56,25 +56,20 @@ end # if none exists, return (nothing, nothing) function versionconstraint(ex) if isexpr(ex, :call) && ex.args[1] in COMPARISON_OPS - return versionconstraint( - Expr(:comparison, ex.args[2], ex.args[1], ex.args[3])) - elseif isexpr(ex, :comparison) - if in(:VERSION, ex.args) - for i = 1:2:length(ex.args) - a = ex.args[i] - if a == :VERSION - continue - end - if !isexpr(a, :macrocall) || a.args[1] != Symbol("@v_str") || - !(typeof(a.args[2]) <: AbstractString) - return (nothing, nothing) - end + if length(ex.args) == 3 + isversionfirst = :VERSION == ex.args[2] + constraint = simplify_literal( + isversionfirst ? ex.args[3] : ex.args[2]) + if isa(constraint, VersionNumber) + pred = ver -> getfield(Base, ex.args[1])( + isversionfirst ? ver : constraint, + isversionfirst ? constraint : ver) + return (pred, !pred) end - l = eval(Main, Expr(:(->), :VERSION, ex)) - return (l, _ -> !(l(_))) - else - return (nothing, nothing) end + return (nothing, nothing) + elseif isexpr(ex, :comparison) + return versionconstraint(split_comparison(ex)) elseif isexpr(ex, :(&&)) vc1 = versionconstraint(ex.args[1]) vc2 = versionconstraint(ex.args[2]) diff --git a/src/exprutils.jl b/src/exprutils.jl new file mode 100644 index 0000000..e898770 --- /dev/null +++ b/src/exprutils.jl @@ -0,0 +1,47 @@ +module ExpressionUtils + +using Base.Meta + +export split_comparison, simplify_literal + +""" + split_comparison(::Expr) + +Split a :comparison expression into an equivalent :&& expression, given that +each component of the comparison is pure. +""" +function split_comparison(ex) + if !isexpr(ex, :comparison) + throw(ArgumentError("expected a comparison expression, got a $(ex.head)")) + end + left = ex.args[1] + op = ex.args[2] + right = ex.args[3] + remainder = ex.args[3:end] + if length(remainder) == 1 + :($op($left, $right)) + else + :($op($left, $right) && + $(split_comparison(Expr(:comparison, remainder...)))) + end +end + +""" + simplify_literal(::Expr) + +Simplify certain macros into the literals they produce. + +Simplifications performed include: + + - v"x.y.z" literals are simplified into `VersionNumber` objects. +""" +function simplify_literal(ex) + if isexpr(ex, :macrocall) && ex.args[1] == Symbol("@v_str") && + isa(ex.args[2], AbstractString) + VersionNumber(ex.args[2]) + else + ex + end +end + +end From 260352fdf680c59450fdd704da345361347b59f8 Mon Sep 17 00:00:00 2001 From: Fengyang Wang Date: Thu, 19 Jan 2017 17:45:49 -0500 Subject: [PATCH 3/4] Various typeof to isa modernizations --- src/functions.jl | 40 ++++++++++++++++++++-------------------- src/guesstype.jl | 18 +++++------------- src/pragma.jl | 4 ++-- src/variables.jl | 30 +++++++++++++----------------- 4 files changed, 40 insertions(+), 52 deletions(-) diff --git a/src/functions.jl b/src/functions.jl index e56f0bc..ba19bce 100644 --- a/src/functions.jl +++ b/src/functions.jl @@ -55,7 +55,7 @@ function initcommoncollfuncs() end function lintfuncargtype(ex, ctx::LintContext) - if typeof(ex) <: Expr && ex.head == :curly + if isexpr(ex, :curly) st = 2 en = 1 if ex.args[1] == :Array @@ -75,7 +75,7 @@ end # a constructor for a type. We would check # * if the function name matches the type name function lintfunction(ex::Expr, ctx::LintContext; ctorType = Symbol(""), isstaged=false) - if length(ex.args) == 1 && typeof(ex.args[1]) == Symbol + if length(ex.args) == 1 && isa(ex.args[1], Symbol) # generic function without methods return end @@ -97,7 +97,7 @@ function lintfunction(ex::Expr, ctx::LintContext; ctorType = Symbol(""), isstage elseif isexpr(ex.args[1].args[1], :(.)) fname = ex.args[1].args[1] push!(ctx.callstack[end].functions, fname.args[end]) - elseif typeof(ex.args[1].args[1]) == Symbol + elseif isa(ex.args[1].args[1], Symbol) fname = ex.args[1].args[1] push!(ctx.callstack[end].functions, fname) elseif !isa(ex.args[1].args[1], Expr) @@ -108,7 +108,7 @@ function lintfunction(ex::Expr, ctx::LintContext; ctorType = Symbol(""), isstage push!(ctx.callstack[end].functions, fname) for i in 2:length(ex.args[1].args[1].args) adt = ex.args[1].args[1].args[i] - if typeof(adt) == Symbol + if isa(adt, Symbol) if in(adt, knowntypes) msg(ctx, :E534, adt, "introducing a new name for an implicit " * "argument to the function, use {T<:$(adt)}") @@ -161,7 +161,7 @@ function lintfunction(ex::Expr, ctx::LintContext; ctorType = Symbol(""), isstage assertions = Dict{Symbol, Any}() # e.g. x::Int resolveArguments = (sube, position) -> begin # zero position means it's not called at the top level - if typeof(sube) == Symbol + if isa(sube, Symbol) if in(sube, argsSeen) msg(ctx, :E331, sube, "duplicate argument") end @@ -176,13 +176,13 @@ function lintfunction(ex::Expr, ctx::LintContext; ctorType = Symbol(""), isstage return sube elseif sube.head == :parameters for (j,kw) in enumerate(sube.args) - if typeof(kw)==Expr && kw.head == :(...) + if isexpr(kw, :(...)) if j != length(sube.args) msg(ctx, :E412, kw, "named ellipsis ... can only be the last argument") return end sym = resolveArguments(kw, 0) - if typeof(sym)== Symbol + if isa(sym, Symbol) if isstaged assertions[sym] = Type else @@ -191,7 +191,7 @@ function lintfunction(ex::Expr, ctx::LintContext; ctorType = Symbol(""), isstage end end return - elseif typeof(kw) != Expr || (kw.head != :(=) && kw.head != :kw) + elseif !isexpr(kw, [:(=), :kw]) msg(ctx, :E423, kw, "named keyword argument must have a default") return else @@ -206,7 +206,7 @@ function lintfunction(ex::Expr, ctx::LintContext; ctorType = Symbol(""), isstage sym = resolveArguments(sube.args[1], 0) if !isstaged rhstype = guesstype(sube.args[2], ctx) - if typeof(sym) == Symbol + if isa(sym, Symbol) typeRHShints[sym] = rhstype end end @@ -214,7 +214,7 @@ function lintfunction(ex::Expr, ctx::LintContext; ctorType = Symbol(""), isstage if length(sube.args) > 1 sym = resolveArguments(sube.args[1], 0) if !isstaged - if typeof(sym) == Symbol + if isa(sym, Symbol) dt = Any try dt = parsetype(sube.args[2]) @@ -234,7 +234,7 @@ function lintfunction(ex::Expr, ctx::LintContext; ctorType = Symbol(""), isstage msg(ctx, :E413, sube, "positional ellipsis ... can only be the last argument") end sym = resolveArguments(sube.args[1], 0) - if typeof(sym) == Symbol + if isa(sym, Symbol) if isstaged assertions[sym] = Tuple{Vararg{Type}} elseif haskey(assertions, sym) @@ -343,7 +343,7 @@ function lintlambda(ex::Expr, ctx::LintContext) end resolveArguments = (sube) -> begin - if typeof(sube) == Symbol + if isa(sube, Symbol) checklambdaarg(sube) stacktop.localarguments[end][sube] = VarInfo(ctx.line) #= # until lambda supports named args, keep this commented @@ -367,7 +367,7 @@ function lintlambda(ex::Expr, ctx::LintContext) end end - if typeof(ex.args[1]) == Symbol + if isa(ex.args[1], Symbol) resolveArguments(ex.args[1]) elseif isexpr(ex.args[1], :tuple) for i = 1:length(ex.args[1].args) @@ -385,7 +385,7 @@ end function lintfunctioncall(ex::Expr, ctx::LintContext; inthrow::Bool=false) if ex.args[1] == :include - if typeof(ex.args[2]) <: AbstractString + if isa(ex.args[2], AbstractString) inclfile = string(ex.args[2]) else inclfile = "" @@ -441,7 +441,7 @@ function lintfunctioncall(ex::Expr, ctx::LintContext; inthrow::Bool=false) skiplist = Int[] - if typeof(ex.args[1]) == Symbol && haskey(commoncollmethods, ex.args[1]) + if isa(ex.args[1], Symbol) && haskey(commoncollmethods, ex.args[1]) known=true s = ex.args[1] typesig = Any[] @@ -462,8 +462,8 @@ function lintfunctioncall(ex::Expr, ctx::LintContext; inthrow::Bool=false) #splice! allows empty range such as 3:2, it means inserting an array # between position 2 and 3, without taking out any value. if ex.args[1] == Symbol("splice!") && Meta.isexpr(ex.args[3], :(:)) && - length(ex.args[3].args) == 2 && typeof(ex.args[3].args[1]) <: Real && - typeof(ex.args[3].args[2]) <: Real && ex.args[3].args[2] < ex.args[3].args[1] + length(ex.args[3].args) == 2 && isa(ex.args[3].args[1], Real) && + isa(ex.args[3].args[2], Real) && ex.args[3].args[2] < ex.args[3].args[1] push!(skiplist, 3) end @@ -486,7 +486,7 @@ function lintfunctioncall(ex::Expr, ctx::LintContext; inthrow::Bool=false) end st = 2 - if ex.args[1] == :ifelse && typeof(ex.args[2]) == Expr + if ex.args[1] == :ifelse lintboolean(ex.args[2], ctx) st = 3 known = true @@ -500,7 +500,7 @@ function lintfunctioncall(ex::Expr, ctx::LintContext; inthrow::Bool=false) if isexpr(ex.args[1], :(.)) lintexpr(ex.args[1], ctx) - elseif typeof(ex.args[1]) == Symbol + elseif isa(ex.args[1], Symbol) push!(ctx.callstack[end].calledfuncs, ex.args[1]) end @@ -514,7 +514,7 @@ function lintfunctioncall(ex::Expr, ctx::LintContext; inthrow::Bool=false) end end - if !inthrow && typeof(ex.args[1]) == Symbol + if !inthrow && isa(ex.args[1], Symbol) s = lowercase(string(ex.args[1])) if contains(s,"error") || contains(s,"exception") || contains(s,"mismatch") || contains(s,"fault") try diff --git a/src/guesstype.jl b/src/guesstype.jl index 78978a5..6589c8f 100644 --- a/src/guesstype.jl +++ b/src/guesstype.jl @@ -10,27 +10,19 @@ valuetype{K,V}(::Type{Associative{K,V}}) = V keytype{T<:Associative}(::Type{T}) = keytype(supertype(T)) valuetype{T<:Associative}(::Type{T}) = valuetype(supertype(T)) -function isAnyOrTupleAny(x) - if x == Any - return true - elseif typeof(x) <: Tuple - return all(y->y == Any, x) - end - return false -end - -function evaltype(ex) +function evaltype(ex::Symbol) ret = Any try - ret = eval(Main, ex) + ret = getfield(Base, ex) end return isa(ret, Type) ? ret : Any end +evaltype(ex) = Any # ex should be a type. figure out what it is function parsetype(ex) ret = Any - if typeof(ex) <: Symbol + if isa(ex, Symbol) return evaltype(ex) elseif typeof(ex) <: Expr if isexpr(ex, :curly) @@ -288,7 +280,7 @@ function guesstype(ex, ctx::LintContext) end elt = evaltype(ex.args[2]) - if length(sig) >= 1 && sig[1] == Type + if length(sig) >= 1 && sig[1] <: Type if length(sig) == 2 && isexpr(ex.args[3], :tuple) return Array{elt, length(ex.args[3].args)} elseif length(sig) == 2 && sig[2] <: Tuple && all(x->x <: Integer, sig[2]) diff --git a/src/pragma.jl b/src/pragma.jl index 6597108..90fa0a7 100644 --- a/src/pragma.jl +++ b/src/pragma.jl @@ -1,5 +1,5 @@ function lintlintpragma(ex::Expr, ctx::LintContext) - if length(ex.args) >= 2 && typeof(ex.args[2]) <: AbstractString + if length(ex.args) >= 2 && isa(ex.args[2], AbstractString) m = match(r"^((Print)|(Info)|(Warn)|(Error)) ((type)|(me)|(version)) +(.+)"s, ex.args[2]) if m != nothing action = m.captures[1] @@ -11,7 +11,7 @@ function lintlintpragma(ex::Expr, ctx::LintContext) msg(ctx, :E138, rest_str, "incomplete pragma expression") str = "" else - str = "typeof(" * rest_str * ") == " * string(guesstype(v, ctx)) + str = "typeof($rest_str) == $(guesstype(v, ctx))" end elseif infotype == "me" str = rest_str diff --git a/src/variables.jl b/src/variables.jl index a871435..d1ee270 100644 --- a/src/variables.jl +++ b/src/variables.jl @@ -98,7 +98,7 @@ end function lintglobal(ex::Expr, ctx::LintContext) for sym in ex.args - if typeof(sym) == Symbol + if isa(sym, Symbol) if !haskey(ctx.callstack[end].declglobs, sym) register_global( ctx, @@ -117,17 +117,11 @@ end function lintlocal(ex::Expr, ctx::LintContext) n = length(ctx.callstack[end].localvars) for sube in ex.args - if typeof(sube)==Symbol + if isa(sube, Symbol) ctx.callstack[end].localvars[n][sube] = VarInfo(ctx.line) - continue - end - if typeof(sube) != Expr - msg(ctx, :E135, sube, "local declaration not understood by Lint") - continue - end - if sube.head == :(=) + elseif isexpr(sube, :(=)) lintassignment(sube, :(=), ctx; islocal = true) - elseif sube.head == :(::) + elseif isexpr(sube, :(::)) sym = sube.args[1] vi = VarInfo(ctx.line) try @@ -141,16 +135,18 @@ function lintlocal(ex::Expr, ctx::LintContext) vi.typeexpr = sube.args[2] end ctx.callstack[end].localvars[n][sym] = vi + else + msg(ctx, :E135, sube, "local declaration not understood by Lint") end end end function resolveLHSsymbol(ex, syms::Array{Any,1}, ctx::LintContext, assertions::Dict{Symbol,Any}) - if typeof(ex) == Symbol + if isa(ex, Symbol) push!(syms, ex) - elseif typeof(ex) == Expr + elseif isa(ex, Expr) if ex.head == :(::) - if typeof(ex.args[1]) == Symbol + if isa(ex.args[1], Symbol) assertions[ex.args[1]]=ex.args[2] end resolveLHSsymbol(ex.args[1], syms, ctx, assertions) @@ -202,7 +198,7 @@ function lintassignment(ex::Expr, assign_ops::Symbol, ctx::LintContext; islocal end end - if typeof(rhstype) != Symbol && rhstype <: Tuple && length(rhstype.parameters) != tuplelen && !isForLoop + if !isa(rhstype, Symbol) && rhstype <: Tuple && length(rhstype.parameters) != tuplelen && !isForLoop if tuplelen > 1 msg(ctx, :E418, rhstype, "RHS is a tuple, $tuplelen of " * "$(length(rhstype.parameters)) variables used") @@ -210,7 +206,7 @@ function lintassignment(ex::Expr, assign_ops::Symbol, ctx::LintContext; islocal end for (symidx, s) in enumerate(syms) - if typeof(s) != Symbol # a.b or a[b] + if !isa(s, Symbol) # a.b or a[b] if isexpr(s, [:(.), :ref]) containertype = guesstype(s.args[1], ctx) if containertype != Any && isa(containertype, Type) && !containertype.mutable @@ -258,7 +254,7 @@ function lintassignment(ex::Expr, assign_ops::Symbol, ctx::LintContext; islocal dt = eval(Main, assertions[s]) if isa(dt, Type) vi.typeactual = dt - if !isAnyOrTupleAny(dt) && !isAnyOrTupleAny(rhstype) && !(rhstype <: dt) + if typeintersect(dt, rhstype) == Union{} msg(ctx, :I572, "assert $(s) type= $(dt) but assign a value of " * "$(rhstype)") end @@ -293,7 +289,7 @@ function lintassignment(ex::Expr, assign_ops::Symbol, ctx::LintContext; islocal vi.typeactual <: Number && prevvi.typeactual <: Array && assign_ops != :(=) continue - elseif !isAnyOrTupleAny(vi.typeactual) && typeof(vi.typeactual) != Symbol && !(vi.typeactual <: prevvi.typeactual) && + elseif vi.typeactual ≠ Any && !isa(vi.typeactual, Symbol) && !(vi.typeactual <: prevvi.typeactual) && !(vi.typeactual <: AbstractString && prevvi.typeactual <: vi.typeactual) && !pragmaexists("Ignore unstable type variable $(s)", ctx) msg(ctx, :W545, s, "previously used variable has apparent type " * From d7ac0cd97a2e3cb9b47eaa03669cfa3b152d66bf Mon Sep 17 00:00:00 2001 From: Fengyang Wang Date: Thu, 19 Jan 2017 21:11:36 -0500 Subject: [PATCH 4/4] Fix a large number of test cases for 0.6 --- src/Lint.jl | 2 + src/functions.jl | 2 +- src/guesstype.jl | 92 ++++++++++++++++++++++++++------------------- src/statictype.jl | 20 ++++++++++ src/variables.jl | 42 ++++++++++----------- test/array.jl | 20 +++++----- test/funcall.jl | 4 +- test/misuse.jl | 4 +- test/server.jl | 4 +- test/stagedfuncs.jl | 4 +- test/typecheck.jl | 2 +- 11 files changed, 115 insertions(+), 81 deletions(-) create mode 100644 src/statictype.jl diff --git a/src/Lint.jl b/src/Lint.jl index b070cde..711d875 100644 --- a/src/Lint.jl +++ b/src/Lint.jl @@ -23,6 +23,8 @@ import Base: == include("exprutils.jl") using .ExpressionUtils +include("statictype.jl") + include("linttypes.jl") include("messages.jl") include("knownsyms.jl") diff --git a/src/functions.jl b/src/functions.jl index ba19bce..b03955a 100644 --- a/src/functions.jl +++ b/src/functions.jl @@ -293,7 +293,7 @@ function lintfunction(ex::Expr, ctx::LintContext; ctorType = Symbol(""), isstage if ctorType != Symbol("") && fname == ctorType t = guesstype(ex.args[2], ctx) if isa(t, Type) - if t.name.name != ctorType + if t ≠ Any && t.name.name != ctorType msg(ctx, :E611, "constructor doesn't seem to return the constructed object") end elseif t != ctorType diff --git a/src/guesstype.jl b/src/guesstype.jl index 6589c8f..61268b9 100644 --- a/src/guesstype.jl +++ b/src/guesstype.jl @@ -10,6 +10,15 @@ valuetype{K,V}(::Type{Associative{K,V}}) = V keytype{T<:Associative}(::Type{T}) = keytype(supertype(T)) valuetype{T<:Associative}(::Type{T}) = valuetype(supertype(T)) +function arraytype_dims(elt, dimst) + tuplen = StaticTypeAnalysis.length(dimst) + if isnull(tuplen) + return Array{elt} + else + return Array{elt, get(tuplen)} + end +end + function evaltype(ex::Symbol) ret = Any try @@ -17,7 +26,7 @@ function evaltype(ex::Symbol) end return isa(ret, Type) ? ret : Any end -evaltype(ex) = Any +evaltype(::Any) = Any # ex should be a type. figure out what it is function parsetype(ex) @@ -125,7 +134,14 @@ function guesstype(ex, ctx::LintContext) end end try - return typeof(eval(ex)) + if isdefined(Base, ex) + val = getfield(Base, ex) + if isa(val, Type) + return Type{val} + else + return typeof(val) + end + end end return Any end @@ -191,23 +207,35 @@ function guesstype(ex, ctx::LintContext) return tmp end - if isexpr(ex, :call) && ex.args[1] == :enumerate - return Enumerate{guesstype(ex.args[2], ctx)} - end - if isexpr(ex, :call) fn = ex.args[1] - if fn == :int + argtypes = map(x -> guesstype(x, ctx), ex.args[2:end]) + if isdefined(Core.Inference, :return_type) + if isa(fn, Symbol) && isdefined(Base, fn) && + all(x -> isa(x, Type) && isleaftype(x), argtypes) + inferred = Core.Inference.return_type( + getfield(Base, fn), + Tuple{argtypes...}) + if inferred ≠ Any + return inferred + end + end + end + if fn == :enumerate + return Enumerate{guesstype(ex.args[2], ctx)} + elseif fn == :finalizer + return Void + elseif fn == :Int return Int - elseif fn == :int8 + elseif fn == :Int8 return Int8 - elseif fn == :int16 + elseif fn == :Int16 return Int16 - elseif fn == :int32 + elseif fn == :Int32 return Int32 - elseif fn == :int64 + elseif fn == :Int64 return Int64 - elseif fn == :float + elseif fn == :Float64 return Float64 elseif fn == :Complex return Complex @@ -261,8 +289,8 @@ function guesstype(ex, ctx::LintContext) lastargtype = guesstype(ex.args[3], ctx) if lastargtype <: Integer return Array{elt, 1} - elseif lastargtype <: Tuple && all(x->x<:Integer, lastargtype) - return Array{elt, length(lastargtype.parameters)} + elseif lastargtype <: Tuple{Vararg{Integer}} + return arraytype_dims(elt, lastargtype) else return Array{elt} end @@ -274,17 +302,14 @@ function guesstype(ex, ctx::LintContext) end if isexpr(ex, :call) && in(ex.args[1], [:zeros, :ones]) - sig = Any[] - for i = 2:length(ex.args) - push!(sig, guesstype(ex.args[i], ctx)) - end + sig = map(x -> guesstype(x, ctx), ex.args[2:end]) - elt = evaltype(ex.args[2]) if length(sig) >= 1 && sig[1] <: Type + elt = evaltype(ex.args[2]) if length(sig) == 2 && isexpr(ex.args[3], :tuple) return Array{elt, length(ex.args[3].args)} - elseif length(sig) == 2 && sig[2] <: Tuple && all(x->x <: Integer, sig[2]) - return Array{elt, length(sig[2].parameters)} + elseif length(sig) == 2 && sig[2] <: Tuple{Vararg{Integer}} + return arraytype_dims(elt, sig[2]) else return Array{elt, length(ex.args)-2} end @@ -297,7 +322,7 @@ function guesstype(ex, ctx::LintContext) end end - if isexpr(ex, :call) && in(ex.args[1], [:slicedim, :transpose]) + if isexpr(ex, :call) && ex.args[1] == :transpose fst = guesstype(ex.args[2], ctx) return fst end @@ -336,13 +361,13 @@ function guesstype(ex, ctx::LintContext) if !(sig[1] <: AbstractArray) return Any end - eletyp = eltype(sig[1]) + eletyp = sig[1] == Union{} ? Union{} : eltype(sig[1]) # dump(eletyp) if length(sig)==2 if sig[2] <: Number return Array{eletyp, 1} - elseif sig[2] <: Tuple - return Array{eletyp, length(sig[2].parameters)} + elseif sig[2] <: Tuple{Vararg{Integer}} + return arraytype_dims(eletyp, sig[2]) else return Array{eletyp} end @@ -389,7 +414,7 @@ function guesstype(ex, ctx::LintContext) end ktypeactual = guesstype(ex.args[2], ctx) if ktypeactual <: Integer - return eltype(partyp) + return partyp == Union{} ? Union{} : eltype(partyp) elseif isexpr(ex.args[2], :(:)) # range too return partyp elseif isexpr(ex.args[2], :call) && ex.args[2].args[1] == :Colon @@ -398,7 +423,7 @@ function guesstype(ex, ctx::LintContext) return Any end elseif partyp <: AbstractArray - eletyp = eltype(partyp) + eletyp = partyp == Union{} ? Union{} : eltype(partyp) try nd = ndims(partyp) # This may throw if we couldn't infer the dimension tmpdim = nd - (length(ex.args)-1) @@ -453,18 +478,7 @@ function guesstype(ex, ctx::LintContext) return partyp end elseif partyp <: Tuple - if isempty(partyp.parameters) - return Any - end - if length(partyp.parameters) == 1 || partyp.parameters[1].name.name == :Vararg - if typeof(partyp.parameters[1].parameters[1]) <: Type - return evaltype(partyp.parameters[1].parameters[1].name.name) - end - end - elt = partyp.parameters[1] - if all(x->x == elt, partyp.parameters) - return elt - end + return partyp == Union{} ? Union{} : eltype(partyp) #= elseif isdefined(Main, :AbstractDataFrame) && partyp <: AbstractDataFrame ktypeactual = guesstype(ex.args[2], ctx) diff --git a/src/statictype.jl b/src/statictype.jl new file mode 100644 index 0000000..4b11025 --- /dev/null +++ b/src/statictype.jl @@ -0,0 +1,20 @@ +module StaticTypeAnalysis + +""" + StaticTypeAnalysis.length(T::Type) + +If it can be determined that all objects of type `T` have length `n`, then +return `Nullable(n)`. Otherwise, return `Nullable{Int}()`. +""" +length(::Type{Union{}}) = Nullable(0) +length(::Type) = Nullable{Int}() +length{T<:Pair}(::Type{T}) = 2 +if VERSION < v"0.6-" + length{T<:Tuple}(::Type{T}) = Nullable{Int}(Base.length(T.parameters)) +else + include_string(""" + length(::Type{T}) where T <: NTuple{N, Any} where N = Nullable{Int}(N) + """) +end + +end diff --git a/src/variables.jl b/src/variables.jl index d1ee270..9363b01 100644 --- a/src/variables.jl +++ b/src/variables.jl @@ -178,28 +178,32 @@ function lintassignment(ex::Expr, assign_ops::Symbol, ctx::LintContext; islocal lhsIsTuple = Meta.isexpr(ex.args[1], :tuple) rhstype = guesstype(ex.args[2], ctx) - if isForLoop + if isForLoop && isa(rhstype, Type) if rhstype <: Number msg(ctx, :I672, "iteration works for a number but it may be a typo") end - if rhstype <: Tuple - rhstype = Any - elseif rhstype <: Set || rhstype <: Array || rhstype <: Range || rhstype <: Enumerate + if rhstype == Union{} + rhstype = Union{} + elseif rhstype <: Tuple || rhstype <: Set || rhstype <: Array || rhstype <: Range || rhstype <: Enumerate rhstype = eltype(rhstype) elseif rhstype <: Associative # @lintpragma("Ignore unstable type variable rhstype") rhstype = Tuple{keytype(rhstype), valuetype(rhstype)} end - if rhstype <: Tuple && length(rhstype.parameters) != tuplelen - msg(ctx, :I474, rhstype, "iteration generates tuples, " * - "$tuplelen of $(length(rhstype.parameters)) variables used") + if rhstype <: Tuple + computedlength = StaticTypeAnalysis.length(rhstype) + if !isnull(computedlength) && get(computedlength) ≠ tuplelen + msg(ctx, :I474, rhstype, "iteration generates tuples, " * + "$tuplelen of $(length(rhstype.parameters)) variables used") + end end end - if !isa(rhstype, Symbol) && rhstype <: Tuple && length(rhstype.parameters) != tuplelen && !isForLoop - if tuplelen > 1 + if !isa(rhstype, Symbol) && rhstype <: Tuple + computedlength = StaticTypeAnalysis.length(rhstype) + if !isnull(computedlength) && get(computedlength) ≠ tuplelen > 1 msg(ctx, :E418, rhstype, "RHS is a tuple, $tuplelen of " * "$(length(rhstype.parameters)) variables used") end @@ -209,7 +213,7 @@ function lintassignment(ex::Expr, assign_ops::Symbol, ctx::LintContext; islocal if !isa(s, Symbol) # a.b or a[b] if isexpr(s, [:(.), :ref]) containertype = guesstype(s.args[1], ctx) - if containertype != Any && isa(containertype, Type) && !containertype.mutable + if isa(containertype, DataType) && isleaftype(containertype) && !containertype.mutable msg(ctx, :E525, s.args[1], "is of an immutable type $(containertype)") end end @@ -238,9 +242,9 @@ function lintassignment(ex::Expr, assign_ops::Symbol, ctx::LintContext; islocal end vi = VarInfo(ctx.line) # @lintpragma("Ignore incompatible type comparison") - if rhstype == Any || !lhsIsTuple + if isa(rhstype, Type) && !lhsIsTuple rhst = rhstype - elseif rhstype <: Tuple && lhsIsTuple + elseif isa(rhstype, Type) && rhstype <: Tuple && lhsIsTuple if length(rhstype.parameters) <= symidx rhst = Any else @@ -251,15 +255,11 @@ function lintassignment(ex::Expr, assign_ops::Symbol, ctx::LintContext; islocal end try if haskey(assertions, s) - dt = eval(Main, assertions[s]) - if isa(dt, Type) - vi.typeactual = dt - if typeintersect(dt, rhstype) == Union{} - msg(ctx, :I572, "assert $(s) type= $(dt) but assign a value of " * - "$(rhstype)") - end - else - vi.typeexpr = assertions[s] + dt = parsetype(assertions[s]) + vi.typeactual = dt + if typeintersect(dt, rhst) == Union{} + msg(ctx, :I572, "assert $(s) type= $(dt) but assign a value of " * + "$(rhst)") end elseif rhst != Any && !isForLoop vi.typeactual = rhst diff --git a/test/array.jl b/test/array.jl index 76f139a..39b3ab1 100644 --- a/test/array.jl +++ b/test/array.jl @@ -88,44 +88,42 @@ msgs = lintstr(s) @test msgs[2].code == :I271 @test contains(msgs[2].message, "typeof(x2) == Array{Int64,2}") @test msgs[3].code == :I271 -@test contains(msgs[3].message, "typeof(x3) == Array{T,N}") +@test contains(msgs[3].message, "typeof(x3) == $Array") @test msgs[4].code == :I271 @test contains(msgs[4].message, "typeof(x4) == Array{Float64,2}") # more array function s = """ function f(t::Array{Int64,2}, m, n) - x1 = slicedim(t, 2, 1) x2 = reshape(t, 1) x3 = reshape(t, (1,2)) x4 = reshape(m, (1,2)) x5 = reshape(t, n) x6 = reshape(t, 1, 2) x7 = t' - @lintpragma("Info type x1") + x8 = (1, 2) @lintpragma("Info type x2") @lintpragma("Info type x3") @lintpragma("Info type x4") @lintpragma("Info type x5") @lintpragma("Info type x6") @lintpragma("Info type x7") + @lintpragma("Info type x8") end """ msgs = lintstr(s) @test msgs[1].code == :I271 -@test contains(msgs[1].message, "typeof(x1) == Array{Int64,2}") +@test contains(msgs[1].message, "typeof(x2) == Array{Int64,1}") @test msgs[2].code == :I271 -@test contains(msgs[2].message, "typeof(x2) == Array{Int64,1}") +@test contains(msgs[2].message, "typeof(x3) == Array{Int64,2}") @test msgs[3].code == :I271 -@test contains(msgs[3].message, "typeof(x3) == Array{Int64,2}") +@test contains(msgs[3].message, "typeof(x4) == Any") @test msgs[4].code == :I271 -@test contains(msgs[4].message, "typeof(x4) == Any") +@test contains(msgs[4].message, "typeof(x5) == Array{Int64,N}") @test msgs[5].code == :I271 -@test contains(msgs[5].message, "typeof(x5) == Array{Int64,N}") +@test contains(msgs[5].message, "typeof(x6) == Array{Int64,2}") @test msgs[6].code == :I271 -@test contains(msgs[6].message, "typeof(x6) == Array{Int64,2}") -@test msgs[7].code == :I271 -@test contains(msgs[7].message, "typeof(x7) == Array{Int64,2}") +@test contains(msgs[6].message, "typeof(x7) == Array{Int64,2}") s = """ function f(a::Array{Float64}) diff --git a/test/funcall.jl b/test/funcall.jl index fc492c0..276abc2 100644 --- a/test/funcall.jl +++ b/test/funcall.jl @@ -223,11 +223,11 @@ msgs = lintstr(s) @test msgs[1].code == :I271 @test contains(msgs[1].message, "typeof(a) == Array{Any,1}") @test msgs[2].code == :I271 -@test contains(msgs[2].message, "typeof(n) == Int") +@test contains(msgs[2].message, "typeof(n) == Tuple{Int64}") @test msgs[3].code == :I271 @test contains(msgs[3].message, "typeof(tmp) == Array{Any,1}") @test msgs[4].code == :I271 -@test contains(msgs[4].message, "typeof(T) == DataType") +@test contains(msgs[4].message, "typeof(T) == Type") @test msgs[5].code == :I271 @test contains(msgs[5].message, "typeof(tmp2) == Array{Any,1}") @test msgs[6].code == :I271 diff --git a/test/misuse.jl b/test/misuse.jl index 63f26cd..17bf51b 100644 --- a/test/misuse.jl +++ b/test/misuse.jl @@ -50,7 +50,7 @@ if VERSION < v"0.5.0-dev+2959" @test msgs[2].code == :W441 else @test msgs[1].code == :W447 -@test contains(msgs[1].message, "it should be of type DataType") +@test contains(msgs[1].message, "it should be of type Type") @test msgs[2].code == :W447 -@test contains(msgs[2].message, "it should be of type DataType") +@test contains(msgs[2].message, "it should be of type Type") end diff --git a/test/server.jl b/test/server.jl index 1d11c4d..b2cdc74 100644 --- a/test/server.jl +++ b/test/server.jl @@ -12,7 +12,7 @@ write(conn, "empty\n") write(conn, "1\n") write(conn, "\n") -@test readline(conn) == "\n" +@test chomp(readline(conn)) == "" conn = connect(port) @@ -21,7 +21,7 @@ write(conn, "4\n") write(conn, "bad\n") @test contains(readline(conn), "use of undeclared symbol") -@test readline(conn) == "\n" +@test chomp(readline(conn)) == "" # This isn't working on the nightly build. Ideally we explicitly stop the server process (as # it loops forever). It seems to get stopped when the tests end, so it's not necessary. diff --git a/test/stagedfuncs.jl b/test/stagedfuncs.jl index 110931d..3aba7ff 100644 --- a/test/stagedfuncs.jl +++ b/test/stagedfuncs.jl @@ -34,6 +34,6 @@ end """ msgs = lintstr(s) @test msgs[1].code == :I271 -@test contains(msgs[1].message, "typeof(args) == Tuple{Vararg{DataType") +@test contains(msgs[1].message, "typeof(args) == Tuple{Vararg{Type") @test msgs[2].code == :I271 -@test contains(msgs[2].message, "typeof(x) == DataType") +@test contains(msgs[2].message, "typeof(x) == ") diff --git a/test/typecheck.jl b/test/typecheck.jl index 7b45167..8d409ff 100644 --- a/test/typecheck.jl +++ b/test/typecheck.jl @@ -148,7 +148,7 @@ end msgs = lintstr(s) @test msgs[1].code == :E521 @test msgs[1].variable == "a" -@test contains(msgs[1].message, "apparent type DataType is not a container type") +@test contains(msgs[1].message, "apparent type Type") s = """ function f()