Index: src/GenPoly/Lvalue.cc
===================================================================
--- src/GenPoly/Lvalue.cc	(revision 795d4506f70255b7275c3eb2195588d82be797eb)
+++ src/GenPoly/Lvalue.cc	(revision 9a34b5af88e34afea5a43c4d02c330da9e0defc6)
@@ -27,4 +27,5 @@
 #include "SynTree/Mutator.h"
 #include "SymTab/Indexer.h"
+#include "SymTab/Autogen.h"
 #include "ResolvExpr/Resolver.h"
 #include "ResolvExpr/typeops.h"
@@ -41,4 +42,20 @@
 namespace GenPoly {
 	namespace {
+		// TODO: fold this into the general createDeref function??
+		Expression * mkDeref( Expression * arg ) {
+			if ( SymTab::dereferenceOperator ) {
+				VariableExpr * deref = new VariableExpr( SymTab::dereferenceOperator );
+				deref->set_result( new PointerType( Type::Qualifiers(), deref->get_result() ) );
+				Type * base = InitTweak::getPointerBase( arg->get_result() );
+				assertf( base, "expected pointer type in dereference (type was %s)", toString( arg->get_result() ).c_str() );
+				ApplicationExpr * ret = new ApplicationExpr( deref, { arg } );
+				delete ret->get_result();
+				ret->set_result( new ReferenceType( Type::Qualifiers(), base->clone() ) );
+				return ret;
+			} else {
+				return UntypedExpr::createDeref( arg );
+			}
+		}
+
 		struct ReferenceConversions final {
 			Expression * postmutate( CastExpr * castExpr );
@@ -115,22 +132,19 @@
 
 		void fixArg( Expression *& arg, Type * formal ) {
-			// if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( arg ) ) {
-				if ( dynamic_cast<ReferenceType*>( formal ) ) { // xxx - but might be deref, in which case result isn't REALLY a reference, at least not in the sense that we need to add another deref...
-					// doesn't work, for some reason left arg is skipped in assign
-					ReferenceType * refType = safe_dynamic_cast< ReferenceType * >( arg->get_result() ) ;
-					std::cerr << "appexpr arg is non-deref/index intrinsic call" << std::endl;
-					std::cerr << arg << std::endl;
-					PointerType * ptrType = new PointerType( Type::Qualifiers(), refType->get_base()->clone() );
-					delete refType;
-					arg->set_result( ptrType );
-					arg = UntypedExpr::createDeref( arg );
-				}
-
-			// }
+			if ( dynamic_cast<ReferenceType*>( formal ) ) {
+				// if the parameter is a reference, add a dereference to the reference-typed argument.
+				Type * baseType = InitTweak::getPointerBase( arg->get_result() );
+				assertf( baseType, "parameter is reference, arg must be pointer or reference: %s", toString( arg->get_result() ) );
+				PointerType * ptrType = new PointerType( Type::Qualifiers(), baseType->clone() );
+				delete arg->get_result();
+				arg->set_result( ptrType );
+				arg = mkDeref( new CastExpr( arg, arg->get_result()->clone() ) );
+			}
 		}
 
 		Expression * FixIntrinsicArgs::postmutate( ApplicationExpr * appExpr ) {
+			// intrinsic functions don't really take reference-typed parameters, so they require an implicit dereference on their arguments.
 			if ( DeclarationWithType * function = InitTweak::getFunction( appExpr ) ) {
-				if ( function->get_linkage() == LinkageSpec::Intrinsic ) { // intrinsic functions that turn pointers into references
+				if ( function->get_linkage() == LinkageSpec::Intrinsic ) {
 					FunctionType * ftype = GenPoly::getFunctionType( function->get_type() );
 					assertf( ftype, "Function declaration does not have function type." );
@@ -140,5 +154,6 @@
 						std::cerr << "pair<0>: " << arg << std::endl;
 						std::cerr << "pair<1>: " << formal->get_type() << std::endl;
-						if ( isIntrinsicReference( arg ) ) {
+						if ( isIntrinsicReference( arg ) ) { // intrinsic functions that turn pointers into references
+							// if argument is dereference or array subscript, the result isn't REALLY a reference, so it's not necessary to fix the argument
 							std::cerr << "skipping intrinsic reference" << std::endl;
 							continue;
@@ -153,4 +168,11 @@
 
 		Expression * ReferenceConversions::postmutate( CastExpr * castExpr ) {
+			// xxx - is it possible to convert directly between reference types with a different base? E.g.,
+			//   int x;
+			//   (double&)x;
+			// At the moment, I am working off of the assumption that this is illegal, thus the cast becomes redundant
+			// after this pass, so trash the cast altogether. If that changes, care must be taken to insert the correct
+			// pointer casts in the right places.
+
 			// conversion to reference type
 			if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( castExpr->get_result() ) ) {
@@ -162,23 +184,14 @@
 					if ( isIntrinsicReference( castExpr->get_arg() ) ) {
 						Expression * callExpr = castExpr->get_arg();
-						Expression ** arg = nullptr;
-						Expression *& arg0 = InitTweak::getCallArg( callExpr, 0 );
-						if ( dynamic_cast<PointerType *>( arg0->get_result() ) ) {
-							arg = &arg0;
-						} else {
-							arg = &InitTweak::getCallArg( callExpr, 1 );
-						}
-
-						castExpr->set_arg( *arg );
-						*arg = castExpr;
 						std::cerr << "but arg is deref -- &" << std::endl;
 						std::cerr << callExpr << std::endl;
-						// castExpr->set_arg( new AddressExpr( castExpr->get_arg() ) );
-
 						// move environment out to new top-level
 						callExpr->set_env( castExpr->get_env() );
+						castExpr->set_arg( nullptr );
 						castExpr->set_env( nullptr );
+						delete castExpr;
 						return callExpr;
 					}
+					assertf( false, "non-intrinsic reference with cast of reference to reference not yet supported: ", toString( castExpr ) );
 					std::cerr << castExpr << std::endl;
 					return castExpr;
@@ -189,7 +202,10 @@
 					std::cerr << "convert lvalue to reference -- &" << std::endl;
 					std::cerr << castExpr->get_arg() << std::endl;
-					castExpr->set_arg( new AddressExpr( castExpr->get_arg() ) );
-					// return new AddressExpr( castExpr->get_arg() );
-					return castExpr;
+					Expression * ret = new AddressExpr( castExpr->get_arg() );
+					ret->set_env( castExpr->get_env() );
+					castExpr->set_env( nullptr );
+					castExpr->set_arg( nullptr );
+					delete castExpr;
+					return ret;
 				} else {
 					// rvalue to reference conversion -- introduce temporary
@@ -197,4 +213,5 @@
 				assertf( false, "Only conversions to reference from lvalue are currently supported: %s", toString( castExpr ).c_str() );
 			} else if ( ReferenceType * refType = dynamic_cast< ReferenceType * >( castExpr->get_arg()->get_result() ) ) {
+				// conversion from reference to rvalue
 				// should be easy, just need to move deref code up here?
 				std::cerr << "convert reference to rvalue -- *" << std::endl;
@@ -203,14 +220,13 @@
 					return castExpr;
 				}
-				std::cerr << castExpr << std::endl;
-
-				PointerType * ptrType = new PointerType( refType->get_qualifiers(), refType->get_base()->clone() );
-				delete castExpr->get_result();
-				castExpr->set_result( ptrType );
-				Expression * deref = UntypedExpr::createDeref( castExpr );
+				std::cerr << "was = " << castExpr << std::endl;
+
+				Expression * deref = mkDeref( castExpr->get_arg() );
 				deref->set_env( castExpr->get_env() );
+				castExpr->set_arg( nullptr );
 				castExpr->set_env( nullptr );
+				delete castExpr;
+				std::cerr << "now: " << deref << std::endl;
 				return deref;
-				// assertf( false, "Conversions from reference types are not currently supported." );
 			}
 			return castExpr;
