type system revision and new subtype algorithm #18457

Merged
merged 18 commits into from Jan 16, 2017

Conversation

@JeffBezanson
Member

JeffBezanson commented Sep 12, 2016

This implements the plan in #8974. It is now working well enough to build a system image and get a REPL, albeit with inference disabled. I have some demos.

In the internals there are "only" three changes:

  • Types are explicitly quantified by wrapping in UnionAll types, which have two fields: a TypeVar and a type body:
julia> Array
Array{T,N} where N where T
  • Union types now have two fields, pointing to two types to union together (instead of an svec of types). This is just a representation change.
  • There is a new algorithm for computing the subtype relation. It gives drastically more meaningful results, and will replace the code for subtype and intersection in jltypes.c with a significant net code deletion. Working examples:
julia> Tuple{Union{Int,String}} <: Union{Tuple{Int},Tuple{String}}
true

julia> NTuple <: Tuple, Tuple <: NTuple
(true,false)

The second one is issue #18450.

UnionAll types nest arbitrarily, and the signatures of methods with static parameters are UnionAll types, so we now have "triangular" dispatch:

julia> f{T<:Real, A<:AbstractArray{T}}(x::T, y::Vector{A}) = 0
f (generic function with 1 method)

julia> f(1.0f0, [rand(4,4)])
ERROR: MethodError: no method matching f(::Float32, 
 in eval(::Module, ::Any) at ./boot.jl:235SYSTEM: show(lasterr) caused an error

julia> f(1.0f0, [rand(Float32, 4,4)])
0

(Clearly showing the method error isn't working, but that should just be a matter of updating the showing and reflection code in Base.)

The next steps are to get inference working and then fully replace intersection and morespecific with implementations based on the new algorithm.

Edit: Fixes #19159 #18892 #18450 #18348 #17943 #16922 #13165 #12596 #11803 #8915 #8625 #6721 #2552

@tkelman tkelman added this to the 0.6.0 milestone Sep 12, 2016

src/typemap.c
- return jl_types_equal_generic(a, b, useenv);
- }
- return jl_subtype(a, b, 0) && jl_subtype(b, a, 0);
+ return jl_types_equal(a, b);

This comment has been minimized.

@vtjnash

vtjnash Sep 12, 2016

Member

❤️
(can now get rid of this function, those comments, and rip out useenv entirely :)

@vtjnash

vtjnash Sep 12, 2016

Member

❤️
(can now get rid of this function, those comments, and rip out useenv entirely :)

src/alloc.c
JL_GC_PUSH1(&m);
+ int i;
+ for(i=(int)jl_svec_len(tvars)-1; i >= 0 ; i--) {

This comment has been minimized.

@ararslan

ararslan Sep 12, 2016

Member

The spacing seems a little inconsistent with the other fors here. Might be better as

for (i = (int)jl_svec_len(tvars)-1; i >= 0; i--)

Just a suggestion.

As an aside, needless to say this is awesome. You rock!!

@ararslan

ararslan Sep 12, 2016

Member

The spacing seems a little inconsistent with the other fors here. Might be better as

for (i = (int)jl_svec_len(tvars)-1; i >= 0; i--)

Just a suggestion.

As an aside, needless to say this is awesome. You rock!!

@TotalVerb

This comment has been minimized.

Show comment
Hide comment
@TotalVerb

TotalVerb Sep 12, 2016

Contributor

Theoretically, any tuple is NTuple{N, Any} for some value of N, so why shouldn't Tuple <: NTuple?

Nevertheless, this is incredible. 👍

Contributor

TotalVerb commented Sep 12, 2016

Theoretically, any tuple is NTuple{N, Any} for some value of N, so why shouldn't Tuple <: NTuple?

Nevertheless, this is incredible. 👍

@StefanKarpinski

This comment has been minimized.

Show comment
Hide comment
@StefanKarpinski

StefanKarpinski Sep 12, 2016

Member

I'm a bit confused by Tuple{Union{Int,String}} <: Union{Tuple{Int},Tuple{String}} being true. Aren't instances of the LHS any tuples of Ints and Strings while instances of the RHS are tuples of Ints or tuples of Strings but not mixes of both? Shouldn't the inclusion be the other way around?

Member

StefanKarpinski commented Sep 12, 2016

I'm a bit confused by Tuple{Union{Int,String}} <: Union{Tuple{Int},Tuple{String}} being true. Aren't instances of the LHS any tuples of Ints and Strings while instances of the RHS are tuples of Ints or tuples of Strings but not mixes of both? Shouldn't the inclusion be the other way around?

@johnmyleswhite

This comment has been minimized.

Show comment
Hide comment
@johnmyleswhite

johnmyleswhite Sep 12, 2016

Member

I thought Tuple{Union{Int,String}} means either Tuple{Int} or Tuple{String} since there's exactly one element.

Member

johnmyleswhite commented Sep 12, 2016

I thought Tuple{Union{Int,String}} means either Tuple{Int} or Tuple{String} since there's exactly one element.

@StefanKarpinski

This comment has been minimized.

Show comment
Hide comment
@StefanKarpinski

StefanKarpinski Sep 12, 2016

Member

Ah, yes. I was forgetting how the new Tuple type syntax works. Thanks, @johnmyleswhite.

Member

StefanKarpinski commented Sep 12, 2016

Ah, yes. I was forgetting how the new Tuple type syntax works. Thanks, @johnmyleswhite.

@StefanKarpinski

This comment has been minimized.

Show comment
Hide comment
@StefanKarpinski

StefanKarpinski Sep 12, 2016

Member

(I was thinking of Tuple as a hypothetical TTuple type that's like NTuple but with N and T in reverse order.)

Member

StefanKarpinski commented Sep 12, 2016

(I was thinking of Tuple as a hypothetical TTuple type that's like NTuple but with N and T in reverse order.)

@tbreloff

This comment has been minimized.

Show comment
Hide comment
@tbreloff

tbreloff Sep 12, 2016

so we now have "triangular" dispatch

Oh snap! Flashback to my giddy excitement during your JuliaCon 2015 talk :)

so we now have "triangular" dispatch

Oh snap! Flashback to my giddy excitement during your JuliaCon 2015 talk :)

@JeffBezanson

This comment has been minimized.

Show comment
Hide comment
@JeffBezanson

JeffBezanson Sep 13, 2016

Member

@TotalVerb Good point. !(Tuple <: NTuple) is caused by the "diagonal rule". For example a method f{T}(x::T...) only matches arguments that are all of the same concrete type, so it is not the same as f(x::Any...). The type system models this by saying that certain type vars only range over concrete types.

From there, we have two choices:

  1. Disallow NTuple{N, Any}. Since the second parameter can only range over concrete types, substituting Any is not valid.
  2. Allow it, meaning the property U{T} <: U does not hold.

We currently pick (2). While U{T} <: U intuitively seems like it should be true, in practice I don't believe we actually need this property for anything.

Member

JeffBezanson commented Sep 13, 2016

@TotalVerb Good point. !(Tuple <: NTuple) is caused by the "diagonal rule". For example a method f{T}(x::T...) only matches arguments that are all of the same concrete type, so it is not the same as f(x::Any...). The type system models this by saying that certain type vars only range over concrete types.

From there, we have two choices:

  1. Disallow NTuple{N, Any}. Since the second parameter can only range over concrete types, substituting Any is not valid.
  2. Allow it, meaning the property U{T} <: U does not hold.

We currently pick (2). While U{T} <: U intuitively seems like it should be true, in practice I don't believe we actually need this property for anything.

@TotalVerb

This comment has been minimized.

Show comment
Hide comment
@TotalVerb

TotalVerb Sep 13, 2016

Contributor

Ah. So the current rule for function dispatch, that typevars in covariant position only range over concrete types, will be applied to type calculations too? It is certainly nice that this will be made more consistent than it is presently:

julia> test{T}(::Vararg{T,2}) = T
test (generic function with 1 method)

julia> test(1,1.0)
ERROR: MethodError: no method matching test(::Int64, ::Float64)
Closest candidates are:
  test{T}(::T...) at REPL[128]:1

julia> typeof(test).name.mt.defs.sig
Tuple{#test,Vararg{T,2}}

julia> isa((test,1,1.0), ans)
true

!(U{T} <: U) is certainly unintuitive, but I also don't think it's a huge loss. This is already the case with Union, and as far as I can tell will only be the case with things typealiased to Tuple (as no other type is covariant).

Contributor

TotalVerb commented Sep 13, 2016

Ah. So the current rule for function dispatch, that typevars in covariant position only range over concrete types, will be applied to type calculations too? It is certainly nice that this will be made more consistent than it is presently:

julia> test{T}(::Vararg{T,2}) = T
test (generic function with 1 method)

julia> test(1,1.0)
ERROR: MethodError: no method matching test(::Int64, ::Float64)
Closest candidates are:
  test{T}(::T...) at REPL[128]:1

julia> typeof(test).name.mt.defs.sig
Tuple{#test,Vararg{T,2}}

julia> isa((test,1,1.0), ans)
true

!(U{T} <: U) is certainly unintuitive, but I also don't think it's a huge loss. This is already the case with Union, and as far as I can tell will only be the case with things typealiased to Tuple (as no other type is covariant).

@JeffBezanson

This comment has been minimized.

Show comment
Hide comment
@JeffBezanson

JeffBezanson Sep 13, 2016

Member

will be applied to type calculations too?

Yes. That certain typevars range over concrete types is now just a structural property of types, to be followed by all type operations.

Member

JeffBezanson commented Sep 13, 2016

will be applied to type calculations too?

Yes. That certain typevars range over concrete types is now just a structural property of types, to be followed by all type operations.

+unionlen(x::Union) = unionlen(x.a) + unionlen(x.b)
+unionlen(x::ANY) = 1
+
+_uniontypes(x::Union, ts) = (_uniontypes(x.a,ts); _uniontypes(x.b,ts); ts)

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

flip argument order?

@timholy

timholy Sep 13, 2016

Member

flip argument order?

This comment has been minimized.

@JeffBezanson

JeffBezanson Sep 13, 2016

Member

The underscore means you're not allowed to complain about it :)

@JeffBezanson

JeffBezanson Sep 13, 2016

Member

The underscore means you're not allowed to complain about it :)

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

OK 😄

@timholy

timholy Sep 13, 2016

Member

OK 😄

show_comma_array(io, sorted_types, '{', '}')
end
-show(io::IO, x::TypeConstructor) = show(io, x.body)
+function print_without_params(x::ANY)

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

This sounds imperative (I was wondering why it didn't have an IO argument).

@timholy

timholy Sep 13, 2016

Member

This sounds imperative (I was wondering why it didn't have an IO argument).

base/show.jl
+ return show(io, unwrap_unionall(x).name)
+ end
+ show(io, x.body)
+ print(io, " where ")

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

I'm not yet clear on what this indicates

@timholy

timholy Sep 13, 2016

Member

I'm not yet clear on what this indicates

This comment has been minimized.

@JeffBezanson

JeffBezanson Sep 13, 2016

Member

It's a quantifier. e.g. Vector{T} where T<:Integer is the union of all types of the form Vector{T} where T is a subtype of Integer.

(Aside: I'll respond to these since they make a great FAQ, but of course will also add comments and docs later.)

@JeffBezanson

JeffBezanson Sep 13, 2016

Member

It's a quantifier. e.g. Vector{T} where T<:Integer is the union of all types of the form Vector{T} where T is a subtype of Integer.

(Aside: I'll respond to these since they make a great FAQ, but of course will also add comments and docs later.)

src/jltypes.c
+ return 0;
+}
+
+static int has_free_typevars(jl_value_t *v, jl_typeenv_t *env, int inv)

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

comment re meaning of inv (invert?) and why it needs to be an argument (rather than applied by the caller). (EDIT: I assume it's serving an any role for has_bound_typevars.)

@timholy

timholy Sep 13, 2016

Member

comment re meaning of inv (invert?) and why it needs to be an argument (rather than applied by the caller). (EDIT: I assume it's serving an any role for has_bound_typevars.)

src/jltypes.c
+ return b;
+ if (jl_is_leaf_type(a) || jl_is_leaf_type(b))
+ return jl_bottom_type;
+ return b;

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

I love the simplicity, but I don't understand this at all. What happens if this gets called with a=Tuple{Int,Real} and b=Tuple{Real,Int}?

@timholy

timholy Sep 13, 2016

Member

I love the simplicity, but I don't understand this at all. What happens if this gets called with a=Tuple{Int,Real} and b=Tuple{Real,Int}?

This comment has been minimized.

@JeffBezanson

JeffBezanson Sep 13, 2016

Member

This is a stub implementation; it will be rewritten.

@JeffBezanson

JeffBezanson Sep 13, 2016

Member

This is a stub implementation; it will be rewritten.

JL_GC_POP();
return result;
}
-static jl_value_t *inst_type_w_(jl_value_t *t, jl_value_t **env, size_t n,
- jl_typestack_t *stack, int check)
+static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t *stack, int check)

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

The tuple & type instantiation code has always been a little scattered and difficult to figure out which things get called under which circumstances. If nothing else, would be good to have a few comments. (What does w mean?)

@timholy

timholy Sep 13, 2016

Member

The tuple & type instantiation code has always been a little scattered and difficult to figure out which things get called under which circumstances. If nothing else, would be good to have a few comments. (What does w mean?)

src/jltypes.c
+ return jl_is_type(v) || jl_is_typevar(v) || jl_is_symbol(v) || jl_isbits(jl_typeof(v));
+}
+
+static int within_typevar(jl_value_t *t, jl_tvar_t *v)

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

From the name I initially assumed this meant some kind of containment. Add comment.

@timholy

timholy Sep 13, 2016

Member

From the name I initially assumed this meant some kind of containment. Add comment.

src/jltypes.c
+
+// type instantiation
+
+static int valid_type_param(jl_value_t *v)

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

For newbies, add // test whether v can serve as a type parameter

@timholy

timholy Sep 13, 2016

Member

For newbies, add // test whether v can serve as a type parameter

src/jltypes.c
+ return jl_subtype(v->lb, lb) && jl_subtype(ub, v->ub);
+}
+
+jl_value_t *jl_apply_type(jl_value_t *tc, jl_value_t **params, size_t n)

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

// instantiate type tc with type parameters params

@timholy

timholy Sep 13, 2016

Member

// instantiate type tc with type parameters params

JL_GC_POP();
return result;
}
+jl_value_t *instantiate_with(jl_value_t *t, jl_value_t **env, size_t n, jl_typeenv_t *te, jl_typestack_t *stack)

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

instantiate what?

@timholy

timholy Sep 13, 2016

Member

instantiate what?

vararg_sym = jl_symbol("Vararg");
jl_svec_t *tv;
tv = jl_svec2(tvar("T"),tvar("N"));
- jl_vararg_type = jl_new_abstracttype((jl_value_t*)vararg_sym, jl_any_type, tv);
+ jl_vararg_type = (jl_unionall_t*)jl_new_abstracttype((jl_value_t*)vararg_sym, jl_any_type, tv)->name->wrapper;

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

Not sure I fully understand the new vararg representation. What's with all the "bodies"? 😄

@timholy

timholy Sep 13, 2016

Member

Not sure I fully understand the new vararg representation. What's with all the "bodies"? 😄

This comment has been minimized.

@JeffBezanson

JeffBezanson Sep 13, 2016

Member

Valid types can no longer have free type variables: a UnionAll type must be present to bind each var. So Vararg{T,N} now has two layers of UnionAll around it. In the case of Vararg this is a bit awkward, since Vararg itself is not really a valid type, as it doesn't refer to a set of first-class values.

@JeffBezanson

JeffBezanson Sep 13, 2016

Member

Valid types can no longer have free type variables: a UnionAll type must be present to bind each var. So Vararg{T,N} now has two layers of UnionAll around it. In the case of Vararg this is a bit awkward, since Vararg itself is not really a valid type, as it doesn't refer to a set of first-class values.

@@ -0,0 +1,569 @@
+// This file is a part of Julia. License is MIT: http://julialang.org/license
+
+/*

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

Citation to a reference document would be very helpful. If your thesis is still accurate, you could use that.

@timholy

timholy Sep 13, 2016

Member

Citation to a reference document would be very helpful. If your thesis is still accurate, you could use that.

src/subtype.c
+#include "julia.h"
+#include "julia_internal.h"
+
+typedef struct {

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

comment re purpose & meaning of fields

@timholy

timholy Sep 13, 2016

Member

comment re purpose & meaning of fields

src/subtype.c
+ uint32_t stack[10];
+} jl_unionstate_t;
+
+typedef struct _varbinding {

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

comment re purpose & meaning of fields

@timholy

timholy Sep 13, 2016

Member

comment re purpose & meaning of fields

src/subtype.c
+ struct _varbinding *prev;
+} jl_varbinding_t;
+
+typedef struct {

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

comment re purpose & meaning of fields

@timholy

timholy Sep 13, 2016

Member

comment re purpose & meaning of fields

src/subtype.c
+static int statestack_get(jl_unionstate_t *st, int i)
+{
+ assert(i < st->stacksize);
+ return (st->stack[i>>5] & (1<<(i&31))) != 0;

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

explain magic numbers

@timholy

timholy Sep 13, 2016

Member

explain magic numbers

This comment has been minimized.

@JeffBezanson

JeffBezanson Sep 13, 2016

Member

Tim, I appreciate the feedback and the enthusiasm but this is at a very early stage where I'm struggling to get anything working.

@JeffBezanson

JeffBezanson Sep 13, 2016

Member

Tim, I appreciate the feedback and the enthusiasm but this is at a very early stage where I'm struggling to get anything working.

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

Just leave as a TODO list for when you get to it---as an author it's not always obvious what needs commenting. For me, a first order priority is to make sure I can still hack on this sometime in the future.

@timholy

timholy Sep 13, 2016

Member

Just leave as a TODO list for when you get to it---as an author it's not always obvious what needs commenting. For me, a first order priority is to make sure I can still hack on this sometime in the future.

src/subtype.c
+ return R ? subtype(t, choice, e) : subtype(choice, t, e);
+}
+
+// subtype(), but taking apart unions before handling vars

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

yay!

src/subtype.c
+ return subtype(x, y, e);
+}
+
+static void record_var_occurrence(jl_varbinding_t *vb, jl_stenv_t *e)

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

pretty opaque

@timholy

timholy Sep 13, 2016

Member

pretty opaque

src/subtype.c
+ return 0;
+}
+
+static int subtype_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8_t R)

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

maybe issubtype?

This is really cool!

@timholy

timholy Sep 13, 2016

Member

maybe issubtype?

This is really cool!

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

what's R? EDIT: for newbies, even very basic comments like whether this is testing t <: u or u <: t would be enormously helpful (I speak from experience wrapping my head around the current jltypes code).

@timholy

timholy Sep 13, 2016

Member

what's R? EDIT: for newbies, even very basic comments like whether this is testing t <: u or u <: t would be enormously helpful (I speak from experience wrapping my head around the current jltypes code).

This comment has been minimized.

@JeffBezanson

JeffBezanson Sep 13, 2016

Member

Yes, I will definitely add lots of comments before this is final. Since this algorithm is (hopefully) actually correct, everything it does makes sense and should admit a decent explanation.

@JeffBezanson

JeffBezanson Sep 13, 2016

Member

Yes, I will definitely add lots of comments before this is final. Since this algorithm is (hopefully) actually correct, everything it does makes sense and should admit a decent explanation.

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

The correctness, especially for something this complex, is fantastic and obviously the big story here. And comments can wait until this is more finalized. But correctness is not useful as a criterion for deciding whether comments are useful; that's a dangerously-high bar to try to meet. A better criterion is "will we run this code for at least a few months?" Obviously we may not be there with this code yet, which is why it's fine to wait until you're more certain.

But I'm holding you to the fact that there will be comments before merging 😄.

@timholy

timholy Sep 13, 2016

Member

The correctness, especially for something this complex, is fantastic and obviously the big story here. And comments can wait until this is more finalized. But correctness is not useful as a criterion for deciding whether comments are useful; that's a dangerously-high bar to try to meet. A better criterion is "will we run this code for at least a few months?" Obviously we may not be there with this code yet, which is why it's fine to wait until you're more certain.

But I'm holding you to the fact that there will be comments before merging 😄.

src/subtype.c
+ int ans;
+ if (R) {
+ e->envidx++;
+ ans = subtype(t, u->body, e);

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

I wondered if subtype was a constructor, again perhaps issubtype?

@timholy

timholy Sep 13, 2016

Member

I wondered if subtype was a constructor, again perhaps issubtype?

src/subtype.c
+ // in Tuple{...,tn} <: Tuple{...,Vararg{T,N}}, check (lx+1-ly) <: N
+ jl_value_t *N = jl_tparam1(tail);
+ // only do the check if N is free in the tuple type's last parameter
+ if (N != (jl_value_t*)va_p1 && N != (jl_value_t*)va_p2) {

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

wow cool. Can we put numeric constraints on N now or something?

@timholy

timholy Sep 13, 2016

Member

wow cool. Can we put numeric constraints on N now or something?

This comment has been minimized.

@JeffBezanson

JeffBezanson Sep 13, 2016

Member

No, this is just handling the awkwardness of Vararg{T} actually being a UnionAll type. It's kind of a hand optimization of converting a non-Vararg tuple type to Vararg{T,N} where N is the length of the tail of the non-vararg type, and then recursively subtyping the two Vararg types.

@JeffBezanson

JeffBezanson Sep 13, 2016

Member

No, this is just handling the awkwardness of Vararg{T} actually being a UnionAll type. It's kind of a hand optimization of converting a non-Vararg tuple type to Vararg{T,N} where N is the length of the tail of the non-vararg type, and then recursively subtyping the two Vararg types.

src/subtype.c
+
+// state manipulation utilities
+
+static jl_varbinding_t *lookup(jl_stenv_t *e, jl_tvar_t *v)

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

This name is perhaps a bit too generic to be meaningful

@timholy

timholy Sep 13, 2016

Member

This name is perhaps a bit too generic to be meaningful

src/subtype.c
+ e->Lunions.more = e->Runions.more = 0;
+ int found = subtype(x, y, e);
+ if (e->Lunions.more) {
+ // return up to forall_exists_subtype. the recursion must have this shape:

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

does the comment mean that this condition is triggered only under the described circumstances?

@timholy

timholy Sep 13, 2016

Member

does the comment mean that this condition is triggered only under the described circumstances?

+ @test isequal_type(Tuple{Integer,Integer}, Tuple{Integer,Integer})
+
+ @test !issub(Tuple{Int,Int}, Tuple{Int})
+ @test !issub(Tuple{Int}, Tuple{Integer,Integer})

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

Do invariance tests belong here, e.g., !issub(Array{Int,1}, Array{Integer,1})?

@timholy

timholy Sep 13, 2016

Member

Do invariance tests belong here, e.g., !issub(Array{Int,1}, Array{Integer,1})?

+
+# level 2: varargs
+function test_2()
+ @test issub_strict(Tuple{Int,Int}, Tuple{Vararg{Int}})

This comment has been minimized.

@timholy

timholy Sep 13, 2016

Member

somewhere it would be good to be very clear about whether a <: b implies it's true for all possible a and b. For example, !(Tuple{Int,Int} <: Tuple{Vararg{Int,N}}) when N=1 but it is true for any N bigger than 1.

@timholy

timholy Sep 13, 2016

Member

somewhere it would be good to be very clear about whether a <: b implies it's true for all possible a and b. For example, !(Tuple{Int,Int} <: Tuple{Vararg{Int,N}}) when N=1 but it is true for any N bigger than 1.

This comment has been minimized.

@JeffBezanson

JeffBezanson Sep 13, 2016

Member

A <: B now has a "2 quantifier" interpretation: for all possible variable substitutions in A, there exists a variable substitution in B such that A is a subtype of B. That recursion stops at base types with "obvious" subtyping relationships.

@JeffBezanson

JeffBezanson Sep 13, 2016

Member

A <: B now has a "2 quantifier" interpretation: for all possible variable substitutions in A, there exists a variable substitution in B such that A is a subtype of B. That recursion stops at base types with "obvious" subtyping relationships.

@JeffBezanson JeffBezanson merged commit 35b3470 into master Jan 16, 2017

2 checks passed

continuous-integration/appveyor/pr AppVeyor build succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
@iamed2

This comment has been minimized.

Show comment
Hide comment
@iamed2

iamed2 Jan 16, 2017

Contributor

🎉

Contributor

iamed2 commented Jan 16, 2017

🎉

@tkelman

This comment has been minimized.

Show comment
Hide comment
@tkelman

tkelman Jan 16, 2017

Contributor

There's some performance we need to claw back, looks like this added about 10 minutes to the test time on appveyor. Probably comparable on Travis.

Contributor

tkelman commented Jan 16, 2017

There's some performance we need to claw back, looks like this added about 10 minutes to the test time on appveyor. Probably comparable on Travis.

@omus omus referenced this pull request in invenia/Mocking.jl Jan 17, 2017

Merged

Julia 0.6 compatibility change for type system rev #11

@Keno Keno referenced this pull request in JuliaGraphics/ColorTypes.jl Jan 17, 2017

Closed

v0.6 precompile error: new UnionAll type breaks things #65

@Evizero Evizero referenced this pull request in Evizero/UnicodePlots.jl Feb 18, 2017

Merged

Fixes for Julia 0.6 #63

@rofinn rofinn referenced this pull request in JuliaStats/StatsBase.jl Apr 21, 2017

Merged

Made `WeightVec` a subtype of `RealVector` #248

@mauro3 mauro3 referenced this pull request in mauro3/SimpleTraits.jl Aug 15, 2017

Closed

Convert traitfns to use where-syntax #46

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment