Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type inference free comprehensions #11398

Closed
wants to merge 3 commits into from
Closed

Conversation

carnaval
Copy link
Contributor

The first part of this is moving lowering of comprehensions to a julia macro. I think it's a good thing in itself.

The second part is to make comprehension have the same semantic as map that is :

  • remove type_goto and static_typeof
  • use typejoin to compute the array element type
  • be optimistic about the first element type

This implies that we get Vector{Union()} for 0-length input, as was discussed somewhere else.

The cool things :

  • the array type is the same in the repl & in functions, it only depends on the computation not inference. It makes this possible :
julia> [rand() > 0.01 ? 1 : "a" for i=1:4, j=1:4]
4x4 Array{Int64,2}:
 1  1  1  1
 1  1  1  1
 1  1  1  1
 1  1  1  1

julia> [rand() > 0.01 ? 1 : "a" for i=1:4, j=1:4]
4x4 Array{Any,2}:
 1  1  1  1   
 1  1  1   "a"
 1  1  1  1   
 1  1  1   "a"
  • array type is still inferred correctly, with the change that now the result is Union(Array{Union()},Array{T}), but it's ok when you index in it as demonstrated by :
julia> f() = (A = [1.0*i for i=1:4]; A[1])
f (generic function with 1 method)
julia> Base.return_types(f,())[1]
Float64
  • in cases where inference gets it right, this should be close to zero cost since the pessimistic codepath gets optimized away. Removing the Vector{Union()} after one index call is a bit harder since in general it requires backward dataflow analysis. I didn't check and the macro may be emitting ugly things for now so it may need a bit more work.

The code of the macro is ugly. I've also not yet gone through the frontend to remove dead comprehension lowering code. The dict comprehension case should probably also be written. Sysimg code was also a bit butchered in the process to get it work, we would need to go back and make it right. Thanks to @jakebolewski who was easily baited into doing this.

All in all, not close to done but enough for me to get a type_goto free base for now.

@@ -39,7 +37,7 @@ copy(s::SymbolNode) = SymbolNode(s.name, s.typ)

# copy parts of an AST that the compiler mutates
astcopy(x::Union(SymbolNode,Expr)) = copy(x)
astcopy(x::Array{Any,1}) = Any[astcopy(a) for a in x]
astcopy(x::Array{Any,1}) = map(a->astcopy(a),x)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe just map(astcopy, x)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure. all of this is a mess and I'll go back to sort it out.

@carnaval
Copy link
Contributor Author

Added the dict stuff (works the same way) and cleaned up the dead code from inference & frontend (this PR has a negative line count total).

The generated code for the untyped version of [X for Y1 in Z1, Y2 in Z2, ...] looks like :

index = 1
len = length(Z1)*...
if len == 0
   return Array(Union(), 0)
end
s1 = start(Z1)
Y1,s1 = next(Z1)
s2 = start(Z2)
Y2,s2 = next(Z2)
...
v = X
T = typeof(v)
result = Array(T, len)
@goto inner_loop
while !done(Z1,s1)
   Y1,s1 = next(Z1,s1)
   while !done(Z2,s2)
      Y2,s2 = next(Z2,s2)
      ...
      v = X
      S = typeof(v)
      if !(S <: T)
         T = typejoin(T,S)
         result_next = Array(T, len)
         copy!(result_next, 1, result, 1, index-1)
         result = result_next
      end
      @label inner_loop
      result[index] = v
      index += 1
   end
end

@carnaval carnaval force-pushed the ob/goodbye-type_goto branch 2 times, most recently from e3106b1 to 238faa7 Compare May 22, 2015 23:33
@carnaval
Copy link
Contributor Author

This now supports colon in comprehension correctly. The current master one is buggy for more than one colon. This now works :

[[1 2; 3 4] for :, :] == [1 2; 3 4]

and any combination of typed/untyped comprehension with colon/non-colon indices also should. The rule being :

Any colon will be substituted by an implicit index into the result of the comprehension expression. The size of this slice is determined by the size of the corresponding slice in the first result.

There is no error checking if you input an expression which changes size (same as on master), also the expression will be recomputed for each iteration of course. This feature seems very underused, but now it should work correctly :-)

- Move lowering of the comprehension to a julia macro
- Use typejoin to compute the array/dict type while
  being optimistic about the first element
- Fix comprehension colon logic
- Make tests pass
@carnaval
Copy link
Contributor Author

Well my job here is "done". Tests pass with some slight changes here and there. I'm not advocating for merge since I'm sure there are some perf regression everywhere due to the type instability. It is useful to me as is so if no one is interested I'm just gonna leave the PR hanging here for now.

@@ -135,7 +135,13 @@ function length_checked_equal(args...)
n
end

map(f::Function, a::Array{Any,1}) = Any[ f(a[i]) for i=1:length(a) ]
function map(f::Function, a::Array{Any,1})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this rewrite necessary? If so, why?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comprehension macro is not defined yet, so if I remember correctly this was an issue during bootstrap (one of the functions in the macro indirectly called this method, I don't know if that is still the case).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, of course.

@JeffBezanson
Copy link
Member

This is really cool! Awesome work. I think we can seriously consider merging this. Although it would be nice to also base comprehensions on map, but that's definitely work for a future release.

@@ -2,7 +2,7 @@

# parameters limiting potentially-infinite types
const MAX_TYPEUNION_LEN = 3
const MAX_TYPE_DEPTH = 4
const MAX_TYPE_DEPTH = 6
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sneaky... ref #10230

@StefanKarpinski
Copy link
Member

Is there anything preventing us from merging this?

@StefanKarpinski
Copy link
Member

Aside from the need to rebase due to some (hopefully) minor conflicts?

@yuyichao
Copy link
Contributor

I think @carnaval was worrying about type stability caused by type instability caused by Array{Union()}. I'm also wondering what will happen when there are many Array{Union()} passing around....

@StefanKarpinski
Copy link
Member

@JeffBezanson, any thoughts?

@yuyichao
Copy link
Contributor

And here's @carnaval's comment #7258 (comment).

My concern is largely based on #11658 (which can be fixed in general but probably require more polishing than what we want to wait for 0.4)

@StefanKarpinski
Copy link
Member

Ok, yeah that's too bad. Maybe this belongs in Arraymageddon anyway.

@JeffBezanson JeffBezanson mentioned this pull request Jan 24, 2016
3 tasks
@vtjnash
Copy link
Member

vtjnash commented Jul 14, 2016

anything from here still useful?

@DilumAluthge DilumAluthge deleted the ob/goodbye-type_goto branch March 25, 2021 22:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants