►
Description
Walk through the steps to convert the internal representation of closures to use a tuple for the upvar types. In the process, explain a lot about how closures work in rustc itself.
A
A
A
B
So
is
the
idea
that
that
is
a
tuple,
but
inside
that
that
you
zero
to
UK
each
of
them
will
individually
also
be
a
tuple.
Is
it
no
because?
No
because
the
struck,
let's
say
if
there
is
a
struct
and
it
has
some
member
variables,
then
we
want
to
capture
exactly
like
the
entire
path
to
the
lowermost
variable
that
is
being
captured
by
the
by
the
closure
right.
A
A
Okay
and
then-
and
that's
exactly
why
we
have
to
change
this
because
the
set
the
number
of
paths
we
don't
know
until
later
in
compilation
process
and
whereas
before
we
knew
exactly
how
many
variables
we're
going
to
captured
very
early,
we
don't
even
have
to
look
at
the
names.
You
know
look
at
their
types
right
now.
The
only.
B
A
B
A
So
we'll
see
like
it
may
turn
out
that
I'm
wrong.
In
that
case,
we'll
have
to
do
another
refactoring
first,
where
we
introduce,
where
we
make
this,
be
one
filled
with
a
tuple
right
to
be
honest,
I
actually
would
prefer
if
we
did
that
eventually,
just
because
I
would
like
this
to
map
to
a
restaurant,
it's
just
sort
of
nice
conceptually,
but
it
would
be
kind
of
annoying
to
do
and
I.
Don't
know
that
it's
this
step
I
would
want
to
take
like
it
might
be
a
better
to
do
as
a
cleanup
pass
afterwards.
A
A
So,
let's
see
so,
how
would
we
actually
make
this
change
happen?
Well,
first
thing
is,
there's
a
path
called,
or
you
know
about
the
query
system,
I,
think
great
and
so
there's
a
query
called
generics
of
you
can
see
it
here
and
it's
the
one
that
says
for
any
given
def
ID
what
what
is
the
number
of
generic
type
parameters
that
it
has?
Basically,
what
are
the
generic
type
members
declared
on
right,
and
so
you
can
see
here
the
definition
it
starts
out.
A
It
has
this
def
ID
and
it
converts
that
to
a
note
ID,
which
is
old
crap,
that
we
still
have
identifies
a
note
in
here
grabs
that
node
looks
at
it
says
kind
of
what
what
is
this
stuff
I
evasive?
What
kind
of
thing
is
it,
and
the
thing
we're
interested
in
is
this
case,
where
what
we
have
is
a
closure.
So
in
that
case,
actually
what
it's
doing
here
when
it
calls
closure
based
fiu.
So
this
this
is
computing.
The
parent,
def
ID.
A
There
it
is
it:
is
there
actually
like
a
little
bit
of
a
linked
list
of
generics
right?
So
you
have
what
are
the
type
parameters
declared
on
this
particular
thing,
and
then
it
has
a
parent
and
there
and
you
kind
of
inherit,
the
type
parameters
from
your
parent.
This
is
so
you
can
think
of
like
a
method
has
some
type
parameters,
and
then
it's
inside
of
an
info
on
the
info
might
have
type
parameters
and
all
of
those
parameters
are
in
scope
in
the
method
right.
A
A
A
Yeah,
so
here
so
here
when
we
call
closure
base,
definitely
all
that
does
is
basically
walk
up
in
case.
It's
a
closure
inside
a
closure
inside
a
closure.
It
walks
through
the
list
of
folders
to
find
the
innermost
non
closure
and
that's
the
parent
so
because
there's
moisture
out
there
most
innermost
right.
So
if
you,
if
you
have
like
in
both
ooh,
let's
say
a
function,
our
e
let
x
equals.
A
A
A
Ok,
so
I
guess
it
doesn't
really
matter
if
his
innermost
outermost,
because
there's
only
one
function
but
anyway
so
right.
So
then
what
we
do
so
now
we
have
the
parent
def
ID
that
we
match
on
the
actual
thing
itself
that
we're
computing,
the
generic.
So
in
this
case
it's
going
to
be
a
wait.
What
is
this?
Oh.
B
A
If
you
look
here,
you'll
see
that
there's
actually
no,
it
goes
to
the
underscore
case,
and
basically
here
what
we're
doing
is
we're
computing.
What
are
the
generics
that
were
in
that
ast
that,
like
the
user,
wrote
what
were
the
generic
declarations
that
the
user
wrote
right
and
so
for
a
closure?
There
are
none,
because
there
are
no
space
for
them,
but
like
on
a
method
or
something
there
would
be.
That
would
be
like
the
ast
for
this
syntax
here
right.
A
So
this
way
we
get
no
generics
and
then
now
what's
going
on
here,
is
we
start
to
do
some
like
manipulations?
Basically,
what
this
is
doing
is
counting
how
many
generic
parameters
came
from
the
parent
scope,
because
when
we
we
give
each
generic
parameter
an
index.
I'm
gonna
make
a
little
buffer
really
talking
about
this
so
like.
B
A
There's
some
stuff
around
lifetimes,
not
so
excit,
here's
where
we
actually
create
the
type
parameters.
So
all
of
this
is
like
a
no
op
for
closures,
because
this
variable
AST
generics
here
is
going
to
be
the
an
empty
list.
Basically,
so
we're
gonna
now
here
like
iterate
over
all
the
AST
generics,
but
there
aren't
any
so
okay
and
here's
where
we
get
to
closures.
A
A
A
A
A
A
A
So
before
we
were
editing
the
generics
of
query
now
we
have
to
edit
the
code
that
when
you
actually
encounter
a
closure
in
an
expression,
we
have
to
assign
it
a
type
right
right.
That's
the
code
that
kind
of
has
to
be
made
to
match
now,
because
that's
going
to
actually
instantiate
a
reference
to
one
of
these
closure
types
and
it's
going
to
create
the
substitutions
array,
the
substrate
and
it
has
to
have
one
type
for
everything
that
came
from
the
generic
self
query.
So
now
it's
gonna
have
to
many
types.
A
Basically,
because
we're
gonna
have
one
for
Alfaro.
We
just
want
one
for
the
whole
tuple,
so
right
so
we're
so
somewhere
in
here
is
this
with
free
bars,
I
guess:
where
does.
A
A
What
are
the
parameter
types
and
the
argument
types,
and
so
on
that
we
expect
that's
not
really
relevant
to
what
we're
trying
to
do
now.
So
we
can
just
ignore
that
and
go
to
this
check
closure
function,
and
you
see
it
takes
as
argument
the
expected
signature,
because
if
you
don't
care
about
that
right
now,
it's
going
to
do
some
stuff,
and
here
we
go
create.
So
if
you
this
is
the
code,
that's
creating
the
type
variables
for
the
up,
bars
and
I.
A
A
It
looks
like
we
just
get
the
generics
that
it
came
from
that
other
query
and
we
just
do
the
same
number
of
things
as
we're
in
there.
So
this
will
all
kind
of
already
work.
Let's
take,
let's
walk
through
the
codon,
make
sure
I'm
right.
So
what
identity
for
item
does?
Is
it
calls
subs
for
item
I'll?
Make
it
easy
I'll
make
an
example
here.
So,
like
example,.
A
A
A
Okay.
That
makes
sense
right.
Actually
it's
going
to
be
self
I
forget
where
it
will
order
itself,
probably
anyway
same
idea,
and
the
point
of
this
is
those
things
are
actually
not
changing
like
we're,
creating
the
closure
type
from
the
point
of
view
of
of
this
spot
so
from
outside
the
closure,
but
inside
and
outside
the
closure.
We
share
the
same
like
overall
context
right.
So
these
are
so,
if
you
ask
me
like
what
is
the
type
T
in
this
context,
the
answer
is
it's
steam,
it's
a
placeholder
for
T
right
for
some
unknown
20.
A
A
A
Something
which
comes
from
this
closure,
this
disclosure
here
is
code
way,
and
if
you
look
at
that
code,
it
just
creates
fresh
diaper,
please
so,
and
we
we
can
error
out
in
the
case
of
lifetimes,
because
this
is
basically
what
are
the
extra
type
parameters.
We
add
it
to
the
closure
and
we
know
that
they're
never
lifetimes.
A
A
A
Okay,
great
and
then
we
call
make
the
closure
and
all
make
the
closure
does,
is
basically
in
turn
the
pair
of
the
def
ID
of
the
closure.
With
this
substitutions
that
we
have
here,
that's
the
closure
type
and
that's
the
type
of
arts
question
all
done.
Nobody
in
here
in
this
code
actually
cares
about
the.
A
The
types
of
the
out
cars
right
so
they're
just
type
variables
that
don't
get
changed
so
far,
so
good
yeah,
so
where
this
starts
to
change
is
the
up
for
analysis.
A
A
Let's
yeah
so
kind
of
after
we've
done
a
bunch
of
other
stuff.
Then
we
come
back
over
and
now
we
try
to
figure
out
the
types
of
you
deploys
and
the
reason
we
do
that's
the
late
is.
We
want
to
know
how
those
up
Farscape
used
within
the
closure
body
in
order
to
decide
if
they're,
move
or
and
mute
or
what
so
the
details
of
this
I
think
we
talked
about
this
before
a
bit.
A
That's
the
important
thing
is
right:
okay,
so
I'll
just
sort
of
walk
through
quickly,
so
what
the?
But
what
the
inference
does.
First,
we
get
the
type
of
the
closure.
Okay,
that's
fine,
and
they
basically
pull
it
apart
into
the
def
ID
and
the
substitutions
and
of
course
the
type
of
the
closure
had
better
be
closed,
or
else
something
crazy,
and
then
we
for
every
up
variable
we
create
in
this
part
of
the
code.
A
We
start
off,
assuming
that
it's
only
read
from
like
the
most
minimal
requirement
you
could
put
on
this
and
then
when
we
see
if
we
see
that
it's
written
to
will
up
that
to
oh
and
it
gets
mutated.
If
we
see
that
it's
moved
or
up
into
oh
and
gets
move
and
so
on
right.
But
that's
all
in
this,
like
internal
data
structure
for
extranet,
we
don't
care
about
that.
We
go
in
particular
I.
Don't
think
any
of
this
code.
A
A
A
A
So
these
are
the
types
that
now
that
we
know
how
the
variable
is
used.
We
can
compute
a
type
for
each
of
the
free
variables
right.
So,
like
you
go
through
each
of
the
variables
that
are
captured,
we
see
we
read
information
about
what
we
tried
to
do
with
it.
Did
we
need
to
take
ownership
if
we
needed
to
take
ownership?
This
is
that
Miss
then
computing
the
type
of
the
field
and
the
resulting
closure
like.
A
A
A
A
So
that's
what
you
see
going
on
here,
like
if
it's
moved
this
is
computing
for
each
out
bar.
What
is
the
sort
of
type
starting
from
the
type
in
the
parent,
which
would
be
like
a
vector
like
32
it'll?
Add
an
ampersand
make
ref.
This
creates
an
ampersand
type
and
it's
either
the
region,
northern
regions.
It's.
A
A
A
A
B
A
So
yeah,
it's
okay,
so
I'm
good,
yes,
good
that
might
be
I,
don't
know.
Let's
find
out
that
might
be
everything
we
have
to
do.
I
would
be
a
little
surprised.
I
bet,
there's
some
code
somewhere
else,
probably
in
the
code
generator
or
something,
but
you
might
all
the
other
code
might
go
through
the
closure
suppsed.
That
would
be
nice
if
that
were
true,
because
in
that
case,
we've
already
done
the
work.
A
A
Okay,
well,
we
built
it
builds,
but
that
is
to
say
tech
checks.
That's
not
saying
a
whole
lot.
Unfortunately,
this
is
not
the
sort
of
change
where
just
because
it's
a
checks,
you
know
so
I'm,
probably
gonna-
have
to
go
in
a
little
bit.
What
I'll
do
is
all
we
have
a
few
more
minutes,
but
until
then
I'll
push
this
stuff
to
your
branch
when
we're
done
sure
and
I
think,
let's
hope,
let's
see
if
we
can
get
to
the
first
ice,
because
I
don't
know
how
much
experience
you
have
to
bugging
knows
it.
A
What
I
would
I
would
think,
but
we'll
find
out,
like
I,
said
it's
possible
that
that
actually
won't
be
the
case.
That
would
be
really
cool.
The
annoying
thing
this
is
what's
going
to
be
annoying
now.
I,
just
realized
is
that
normally
ices
are
kind
of
good,
because
I
mean
depending
a
point
of
view,
but
because
they
they
die
sort
of
very
early
or
they
die
very
easy.
It's
easy
to
trace
it
to
where
it's
dying,
but
what's
probably
gonna
happen,
is
that
we're
gonna
get
an
ice.
A
The
first
thing
we
do
after
we
build
the
GNU
Compiler.
Is
we
try
to
build
the
core
and
usually
with
a
change
like
this?
That
will
die
because
Lib
core
actually
uses
a
lot
of
language
features
and
that's
annoying
because
debugging
like?
If
you
have
a
lip
standard,
it's
kind
of
nice,
you
can
make
a
minimal
type
a
minimal
example
and
debug
it,
but
debugging
lib
core
when
the
core
feels
super
pain
in
the
neck.
A
A
A
That
would
be
annoying
and
I
think
it
would
probably
get
us
in
trouble.
I.
Think
about
it
because
it
would
break
because
then
code
that
was
compiled
from
the
Bakura
has
a
different
structure
than
code
that
comes
from
the
current
crate.
We're
building
like
when
you
use
the
spike
closures,
are
set
up
differently
and
that
might
cause
problems.
I,
don't
know
so
I,
probably
wouldn't
do
that
actually
we'll
see
anyway.
What
I
would
recommend
is.
A
Least
when,
when
I'm
debugging,
this
sort
of
thing
well
I
always
do
is
turn
on
the
rest.
Logs
dump
out
a
bunch
of
information
and
you
never
double.
You
have
to
add
some
more
across
logs
and
then
that's
where
the
incremental
builds
are
really
nice,
because
you
can
kind
of
get
your
get.
The
output
of
your
new
debug
print
out
much
faster.
A
A
B
B
A
B
A
I'm
not
sure
if
it's
a
hardware,
I've
tested
the
hardware
a
whole
bunch
of
times
that
never
found
a
problem
but
or
what,
but
anyway
all
right.
So
so
by
now
I
know,
though,
if
I
see
some
weird
crash
and
I
love,
I
should
try
it
again,
it's
not
only
all
of
them,
but
it's
usually
anyway.
The
point
is
you
can
build
this
just
like,
so
you
just
build
it
like
a
library,
and
it's
got
all
these
little
weird.
A
B
A
Some
internal
crates
that
it's
built
from
and
the
smallest
of
those
is
called
the
core
and
the
core
is
a
special
one,
because
it's
the
only
core.
It's
the
only
library
that
is
required
for
all
bus
programs,
so
the
rest
of
them
standard.
You
can
opt
out
Earth
by
using
the
no
standard
attribute,
but
you
can't
opt
out
of
Lib
core,
at
least
not
unstable
rust.
We
do
actually
have
a
flag
for
it
because
we
need
it
as
part
of
the
bootstrapping
process,
but
the
the
reason
that
it's
required
it's
very
minimal.
A
Laying
declaration
here
this
is
another
unstable
things.
That's
an
internal
thing
to
the
compiler
saying
this.
This
is
the
size
check.
This
is
not
just
a
trade
name
size
right.
This
is
these
I
stirred
so
and
all
these
similar
leaks
to
these
other
things
and
those
those
those
attributes
can
only
actually
they
can
be
in
the
things
that
are
not
core,
but
they
there
can
only
be
one
crate
like
there
can
only
be
one
trait
that
is
tagged
as
the
size
trait
in
your
entire
crate
grasp
and
because
everybody
has
to
have
Lib
core.
A
It's
always
this
one
right
and
it
would
be
unstable
objects
that
you
every
night
point.
You
know
these
bases
that
are
not
meant
to
be
used
by
at
normal
rest
developers
yeah.
So
that's
that's
what
that's
the
rolled
up
core
place!
That's
why
it's
special
and
why
you
kind
of
want
this
minimal
set
of
things
so
that
the
compiler
can
actually
start
up
and
get
going
without
these
laying
items
it
dies
pretty
early
because
it
has
no
size
tree.