Index: src/AST/Expr.hpp
===================================================================
--- src/AST/Expr.hpp	(revision 79f7875c0d4db049667bcb74cbee7bd1d6779110)
+++ src/AST/Expr.hpp	(revision 79f7875c0d4db049667bcb74cbee7bd1d6779110)
@@ -0,0 +1,134 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Expr.hpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Fri May 10 10:30:00 2019
+// Last Modified By : Aaron B. Moss
+// Created On       : Fri May 10 10:30:00 2019
+// Update Count     : 1
+//
+
+#pragma once
+
+#include <cassert>
+#include <map>
+#include <utility>        // for move
+#include <vector>
+
+#include "Fwd.hpp"        // for UniqueId
+#include "ParseNode.hpp"
+#include "Type.hpp"       // for ptr<Type>
+
+namespace ast {
+
+/// Contains the ID of a declaration and a type that is derived from that declaration, 
+/// but subject to decay-to-pointer and type parameter renaming
+struct ParamEntry {
+	UniqueId decl;
+	ptr<Type> actualType;
+	ptr<Type> formalType;
+	ptr<Expr> expr;
+
+	ParamEntry() : decl( 0 ), actualType( nullptr ), formalType( nullptr ), expr( nullptr ) {}
+	ParamEntry( UniqueId id, Type* actual, Type* formal, Expr* e )
+	: decl( id ), actualType( actual ), formalType( formal ), expr( e ) {}
+};
+
+/// Pre-resolution list of parameters to infer
+using ResnSlots = std::vector<UniqueId>;
+/// Post-resolution map of inferred parameters
+using InferredParams = std::map< UniqueId, ParamEntry >;
+
+/// Base node for expressions
+class Expr : public ParseNode {
+public:
+	/// Saves space (~16 bytes) by combining ResnSlots and InferredParams
+	struct InferUnion {
+		enum { Empty, Slots, Params } mode;
+		union data_t {
+			char def;
+			ResnSlots resnSlots;
+			InferredParams inferParams;
+
+			data_t() : def('\0') {}
+			~data_t() {}
+		} data;
+
+		/// initializes from other InferUnion
+		void init_from( const InferUnion& o ) {
+			switch ( o.mode ) {
+			case Empty:  return;
+			case Slots:  new(&data.resnSlots) ResnSlots{ o.data.resnSlots }; return;
+			case Params: new(&data.inferParams) InferredParams{ o.data.inferParams }; return;
+			}
+		}
+
+		/// initializes from other InferUnion (move semantics)
+		void init_from( InferUnion&& o ) {
+			switch ( o.mode ) {
+			case Empty:  return;
+			case Slots:  new(&data.resnSlots) ResnSlots{ std::move(o.data.resnSlots) }; return;
+			case Params: 
+				new(&data.inferParams) InferredParams{ std::move(o.data.inferParams) }; return;
+			}
+		}
+
+		/// clears variant fields
+		void reset() {
+			switch( mode ) {
+			case Empty:  return;
+			case Slots:  data.resnSlots.~ResnSlots(); return;
+			case Params: data.inferParams.~InferredParams(); return;
+			}
+		}
+
+		InferUnion() : mode(Empty), data() {}
+		InferUnion( const InferUnion& o ) : mode( o.mode ), data() { init_from( o ); }
+		InferUnion( InferUnion&& o ) : mode( o.mode ), data() { init_from( std::move(o) ); }
+		InferUnion& operator= ( const InferUnion& ) = delete;
+		InferUnion& operator= ( InferUnion&& ) = delete;
+		~InferUnion() { reset(); }
+
+		ResnSlots& resnSlots() {
+			switch (mode) {
+			case Empty: new(&data.resnSlots) ResnSlots{}; mode = Slots; // fallthrough
+			case Slots: return data.resnSlots;
+			case Params: assert(!"Cannot return to resnSlots from Params");
+			}
+		}
+
+		InferredParams& inferParams() {
+			switch (mode) {
+			case Slots: data.resnSlots.~ResnSlots(); // fallthrough
+			case Empty: new(&data.inferParams) InferredParams{}; mode = Params; // fallthrough
+			case Params: return data.inferParams;
+			}
+		}
+	};
+
+	ptr<Type> result;
+	ptr<TypeSubstitution> env;
+	InferUnion inferred;
+	bool extension = false;
+
+	Expr(const CodeLocation& loc ) : ParseNode( loc ), result(), env(), inferred() {}
+
+	Expr* set_extension( bool ex ) { extension = ex; return this; }
+
+	virtual Expr* accept( Visitor& v ) override = 0;
+private:
+	virtual Expr* clone() const override = 0;
+};
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/porting.md
===================================================================
--- src/AST/porting.md	(revision 7e895269c55ecce598dc4e83c68d2b412131ea50)
+++ src/AST/porting.md	(revision 79f7875c0d4db049667bcb74cbee7bd1d6779110)
@@ -96,5 +96,6 @@
 
 `Expr`
-* Merged `inferParams`/`resnSlots` into union, as suggested by comment
+* Merged `inferParams`/`resnSlots` into union, as suggested by comment in old version
+  * does imply get_/set_ API, and some care about moving backward
 
 `Label`
