further tweaks to Let handling

this is part of the big compiler refactoring to cut the dependencies
of the compiler front end on nvm stuff.

collective work by Seth, Jason, Robert
reduce usage of `syntax2` method

with an eye towards eliminating it entirely

this required a little reordering of phases. Optimizer used to run
before AgentTypeChecker, but Optimizer replaces primitives in the
code and the new primitive might have a different syntax than the
old prim, so it won't be valid for AgentTypeChecker to be looking
back at `syntax` instead of ahead at `syntax2`.

solution: put Optimizer last. we like this anyway because compilers
generally find correctness problems first, then do
correctness-preserving transformations later. but as a result we
needed to change Optimizer to copy `agentClassString` information over
when it makes new prims, since otherwise the agent type information
recorded there by agentClassString may be lost, making agent type
checks blow up at runtime instead of producing proper runtime
errors.

collective work by Robert, Jason, Seth
eliminate syntax2 entirely

the only remaining use was in Generator.  we got rid of it by
adding a `returnType` method to the CustomGenerated trait,
to give the generator access to the return type without needing
to go through the `syntax2` method

also we had to fix a regression going back to 9c34082, where we
weren't handling `switches` correctly. fixed that by pulling
the switching information out of the Syntax objects entirely,
and just setting the field in the back end prim constructors

collective work by Robert, Jason, and Seth