Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision 6739590feb3dde6143b3fa855a0ee193b12745b7)
+++ src/AST/Pass.hpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
@@ -264,4 +264,7 @@
 	__pass::result1<ast::Stmt> call_accept_as_compound(const ast::Stmt *);
 
+	// requests type environment to be updated (why is it implemented like this?)
+	__pass::result1<ast::Expr> call_accept_top(const ast::Expr *);
+
 	template< template <class...> class container_t >
 	__pass::resultNstmt<container_t> call_accept( const container_t< ptr<Stmt> > & );
@@ -277,4 +280,7 @@
 	template<typename node_t, typename parent_t, typename field_t>
 	void maybe_accept_as_compound(const node_t * &, field_t parent_t::* field);
+
+	template<typename node_t, typename parent_t, typename field_t>
+	void maybe_accept_top(const node_t * &, field_t parent_t::* field);
 
 private:
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision 6739590feb3dde6143b3fa855a0ee193b12745b7)
+++ src/AST/Pass.impl.hpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
@@ -155,9 +155,4 @@
 		__pedantic_pass_assert( expr );
 
-		const ast::TypeSubstitution ** typeSubs_ptr = __pass::typeSubs( core, 0 );
-		if ( typeSubs_ptr && expr->env ) {
-			*typeSubs_ptr = expr->env;
-		}
-
 		auto nval = expr->accept( *this );
 		return { nval != expr, nval };
@@ -171,4 +166,18 @@
 		const ast::Stmt * nval = stmt->accept( *this );
 		return { nval != stmt, nval };
+	}
+
+	template< typename core_t >
+	__pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept_top( const ast::Expr * expr ) {
+		__pedantic_pass_assert( __visit_children() );
+		__pedantic_pass_assert( expr );
+
+		const ast::TypeSubstitution ** typeSubs_ptr = __pass::typeSubs( core, 0 );
+		if ( typeSubs_ptr && expr->env ) {
+			*typeSubs_ptr = expr->env;
+		}
+
+		auto nval = expr->accept( *this );
+		return { nval != expr, nval };
 	}
 
@@ -410,4 +419,28 @@
 
 		auto new_val = call_accept( old_val );
+
+		static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR");
+
+		if( new_val.differs ) {
+			auto new_parent = __pass::mutate<core_t>(parent);
+			new_val.apply(new_parent, field);
+			parent = new_parent;
+		}
+	}
+
+	template< typename core_t >
+	template<typename node_t, typename super_t, typename field_t>
+	void ast::Pass< core_t >::maybe_accept_top(
+		const node_t * & parent,
+		field_t super_t::*field
+	) {
+		static_assert( std::is_base_of<super_t, node_t>::value, "Error deducing member object" );
+
+		if(__pass::skip(parent->*field)) return;
+		const auto & old_val = __pass::get(parent->*field, 0);
+
+		static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR");
+
+		auto new_val = call_accept_top( old_val );
 
 		static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR");
@@ -755,5 +788,5 @@
 
 	if ( __visit_children() ) {
-		maybe_accept( node, &StaticAssertDecl::cond );
+		maybe_accept_top( node, &StaticAssertDecl::cond );
 		maybe_accept( node, &StaticAssertDecl::msg  );
 	}
@@ -797,5 +830,5 @@
 
 	if ( __visit_children() ) {
-		maybe_accept( node, &ExprStmt::expr );
+		maybe_accept_top( node, &ExprStmt::expr );
 	}
 
@@ -838,5 +871,5 @@
 		guard_symtab guard { *this };
 		maybe_accept( node, &IfStmt::inits    );
-		maybe_accept( node, &IfStmt::cond     );
+		maybe_accept_top( node, &IfStmt::cond     );
 		maybe_accept_as_compound( node, &IfStmt::then );
 		maybe_accept_as_compound( node, &IfStmt::else_ );
@@ -856,5 +889,5 @@
 		guard_symtab guard { *this };
 		maybe_accept( node, &WhileDoStmt::inits );
-		maybe_accept( node, &WhileDoStmt::cond  );
+		maybe_accept_top( node, &WhileDoStmt::cond  );
 		maybe_accept_as_compound( node, &WhileDoStmt::body  );
 	}
@@ -874,6 +907,6 @@
 		// xxx - old ast does not create WithStmtsToAdd scope for loop inits. should revisit this later.
 		maybe_accept( node, &ForStmt::inits );
-		maybe_accept( node, &ForStmt::cond  );
-		maybe_accept( node, &ForStmt::inc   );
+		maybe_accept_top( node, &ForStmt::cond  );
+		maybe_accept_top( node, &ForStmt::inc   );
 		maybe_accept_as_compound( node, &ForStmt::body  );
 	}
@@ -889,5 +922,5 @@
 
 	if ( __visit_children() ) {
-		maybe_accept( node, &SwitchStmt::cond  );
+		maybe_accept_top( node, &SwitchStmt::cond  );
 		maybe_accept( node, &SwitchStmt::cases );
 	}
@@ -903,5 +936,5 @@
 
 	if ( __visit_children() ) {
-		maybe_accept( node, &CaseClause::cond  );
+		maybe_accept_top( node, &CaseClause::cond  );
 		maybe_accept( node, &CaseClause::stmts );
 	}
@@ -925,5 +958,5 @@
 
 	if ( __visit_children() ) {
-		maybe_accept( node, &ReturnStmt::expr );
+		maybe_accept_top( node, &ReturnStmt::expr );
 	}
 
@@ -970,5 +1003,5 @@
 		guard_symtab guard { *this };
 		maybe_accept( node, &CatchClause::decl );
-		maybe_accept( node, &CatchClause::cond );
+		maybe_accept_top( node, &CatchClause::cond );
 		maybe_accept_as_compound( node, &CatchClause::body );
 	}
@@ -2057,5 +2090,5 @@
 
 	if ( __visit_children() ) {
-		maybe_accept( node, &SingleInit::value );
+		maybe_accept_top( node, &SingleInit::value );
 	}
 
Index: src/AST/SymbolTable.cpp
===================================================================
--- src/AST/SymbolTable.cpp	(revision 6739590feb3dde6143b3fa855a0ee193b12745b7)
+++ src/AST/SymbolTable.cpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
@@ -65,7 +65,20 @@
 
 Expr * SymbolTable::IdData::combine( const CodeLocation & loc, ResolvExpr::Cost & cost ) const {
-	Expr * ret = ( baseExpr ) ?
-		(Expr *)new MemberExpr{ loc, id, referenceToRvalueConversion( baseExpr, cost ) } :
-		(Expr *)new VariableExpr{ loc, id };
+	Expr * ret;
+	if ( baseExpr ) {
+		if (baseExpr->env) {
+			Expr * base = shallowCopy(baseExpr);
+			const TypeSubstitution * subs = baseExpr->env;
+			base->env = nullptr;
+			ret = new MemberExpr{loc, id, referenceToRvalueConversion( base, cost )};
+			ret->env = subs;
+		}
+		else {
+			ret = new MemberExpr{ loc, id, referenceToRvalueConversion( baseExpr, cost ) };
+		}
+	}
+	else {
+		ret = new VariableExpr{ loc, id };
+	}
 	if ( deleter ) { ret = new DeletedExpr{ loc, ret, deleter }; }
 	return ret;
@@ -772,5 +785,9 @@
 						&& ! dynamic_cast<const UnionInstType *>(rty) ) continue;
 					ResolvExpr::Cost cost = ResolvExpr::Cost::zero;
+					ast::ptr<ast::TypeSubstitution> tmp = expr->env;
+					expr = mutate_field(expr, &Expr::env, nullptr);
 					const Expr * base = ResolvExpr::referenceToRvalueConversion( expr, cost );
+					base = mutate_field(base, &Expr::env, tmp);
+
 					addMembers(
 						rty->aggr(), new MemberExpr{ base->location, dwt, base }, handleConflicts );
Index: src/AST/TypeSubstitution.cpp
===================================================================
--- src/AST/TypeSubstitution.cpp	(revision 6739590feb3dde6143b3fa855a0ee193b12745b7)
+++ src/AST/TypeSubstitution.cpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
@@ -97,5 +97,5 @@
 		TypeSubstitution * newEnv;
 		EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
-		void previsit( FunctionType * ftype ) {
+		void previsit( const FunctionType * ftype ) {
 			// transfer known bindings for seen type variables
 			for (auto & formal : ftype->forall) {
