Index: src/ResolvExpr/CommonType.cc
===================================================================
--- src/ResolvExpr/CommonType.cc	(revision 923558834ec63344a407046c8e08622d03055144)
+++ src/ResolvExpr/CommonType.cc	(revision 4c0fa03a3c9a9471efd0d68bd9371ade49687579)
@@ -696,17 +696,4 @@
 		void postvisit( const ast::BasicType * basic ) {
 			if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) {
-				#warning remove casts when `commonTypes` moved to new AST
-				
-				/*
-				ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)basic2->kind ];
-				if (
-					( ( kind == basic->kind && basic->qualifiers >= basic2->qualifiers )
-						|| widen.first )
-					&& ( ( kind == basic2->kind && basic->qualifiers <= basic2->qualifiers )
-						|| widen.second )
-				) {
-					result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers };
-				}
-				*/
 				ast::BasicType::Kind kind;
 				if (basic->kind != basic2->kind && !widen.first && !widen.second) return;
@@ -719,28 +706,17 @@
 					result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers };
 				}
-				
 			} else if (
 				dynamic_cast< const ast::ZeroType * >( type2 )
 				|| dynamic_cast< const ast::OneType * >( type2 )
 			) {
-				#warning remove casts when `commonTypes` moved to new AST
-				ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)ast::BasicType::SignedInt ];
-				/*
-				if ( // xxx - what does qualifier even do here??
-					( ( basic->qualifiers >= type2->qualifiers )
-						|| widen.first )
-					 && ( ( /* kind != basic->kind && basic->qualifiers <= type2->qualifiers )
-						|| widen.second )
-				) 
-				*/
 				if (widen.second) {
 					result = new ast::BasicType{ basic->kind, basic->qualifiers | type2->qualifiers };
 				}
 			} else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
-				#warning remove casts when `commonTypes` moved to new AST
 				const ast::EnumDecl* enumDecl = enumInst->base;
 				if ( enumDecl->base ) {
 					result = enumDecl->base.get();
 				} else {
+					#warning remove casts when `commonTypes` moved to new AST
 					ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)ast::BasicType::SignedInt ];
 					if (
@@ -763,5 +739,4 @@
 				auto entry = open.find( *var );
 				if ( entry != open.end() ) {
-				// if (tenv.lookup(*var)) {
 					ast::AssertionSet need, have;
 					if ( ! tenv.bindVar(
Index: src/ResolvExpr/ResolveTypeof.h
===================================================================
--- src/ResolvExpr/ResolveTypeof.h	(revision 923558834ec63344a407046c8e08622d03055144)
+++ src/ResolvExpr/ResolveTypeof.h	(revision 4c0fa03a3c9a9471efd0d68bd9371ade49687579)
@@ -30,4 +30,5 @@
 	Type *resolveTypeof( Type*, const SymTab::Indexer &indexer );
 	const ast::Type * resolveTypeof( const ast::Type *, const ResolveContext & );
+	const ast::Type * fixArrayType( const ast::Type *, const ResolveContext & );
 	const ast::ObjectDecl * fixObjectType( const ast::ObjectDecl * decl , const ResolveContext & );
 	const ast::ObjectDecl * fixObjectInit( const ast::ObjectDecl * decl , const ResolveContext &);
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision 923558834ec63344a407046c8e08622d03055144)
+++ src/ResolvExpr/Unify.cc	(revision 4c0fa03a3c9a9471efd0d68bd9371ade49687579)
@@ -32,4 +32,5 @@
 #include "AST/Type.hpp"
 #include "AST/TypeEnvironment.hpp"
+#include "Common/Eval.h"            // for eval
 #include "Common/PassVisitor.h"     // for PassVisitor
 #include "CommonType.hpp"           // for commonType
@@ -779,4 +780,125 @@
 	}
 
+	// Unification of Expressions
+	//
+	// Boolean outcome (obvious):  Are they basically spelled the same?
+	// Side effect of binding variables (subtle):  if `sizeof(int)` ===_expr `sizeof(T)` then `int` ===_ty `T`
+	//
+	// Context:  if `float[VAREXPR1]` ===_ty `float[VAREXPR2]` then `VAREXPR1` ===_expr `VAREXPR2`
+	// where the VAREXPR are meant as notational metavariables representing the fact that unification always
+	// sees distinct ast::VariableExpr objects at these positions
+
+	static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
+		ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
+		WidenMode widen );
+
+	class UnifyExpr final : public ast::WithShortCircuiting {
+		const ast::Expr * e2;
+		ast::TypeEnvironment & tenv;
+		ast::AssertionSet & need;
+		ast::AssertionSet & have;
+		const ast::OpenVarSet & open;
+		WidenMode widen;
+	public:
+		bool result;
+
+	private:
+
+		void tryMatchOnStaticValue( const ast::Expr * e1 ) {
+			Evaluation r1 = eval(e1);
+			Evaluation r2 = eval(e2);
+
+			if ( ! r1.hasKnownValue ) return;
+			if ( ! r2.hasKnownValue ) return;
+
+			if (r1.knownValue != r2.knownValue) return;
+
+			visit_children = false;
+			result = true;
+		}
+
+	public:
+
+		void previsit( const ast::Node * ) { assert(false); }
+
+		void previsit( const ast::Expr * e1 ) {
+			tryMatchOnStaticValue( e1 );
+			visit_children = false;
+		}
+
+		void previsit( const ast::CastExpr * e1 ) {
+			tryMatchOnStaticValue( e1 );
+
+			if (result) {
+				assert (visit_children == false);
+			} else {
+				assert (visit_children == true);
+				visit_children = false;
+
+				auto e2c = dynamic_cast< const ast::CastExpr * >( e2 );
+				if ( ! e2c ) return;
+
+				// inspect casts' target types
+				if ( ! unifyExact(
+					e1->result, e2c->result, tenv, need, have, open, widen ) ) return;
+
+				// inspect casts' inner expressions
+				result = unify( e1->arg, e2c->arg, tenv, need, have, open, widen );
+			}
+		}
+
+		void previsit( const ast::VariableExpr * e1 ) {
+			tryMatchOnStaticValue( e1 );
+
+			if (result) {
+				assert (visit_children == false);
+			} else {
+				assert (visit_children == true);
+				visit_children = false;
+
+				auto e2v = dynamic_cast< const ast::VariableExpr * >( e2 );
+				if ( ! e2v ) return;
+
+				assert(e1->var);
+				assert(e2v->var);
+
+				// conservative: variable exprs match if their declarations are represented by the same C++ AST object
+				result = (e1->var == e2v->var);
+			}
+		}
+
+		void previsit( const ast::SizeofExpr * e1 ) {
+			tryMatchOnStaticValue( e1 );
+
+			if (result) {
+				assert (visit_children == false);
+			} else {
+				assert (visit_children == true);
+				visit_children = false;
+
+				auto e2so = dynamic_cast< const ast::SizeofExpr * >( e2 );
+				if ( ! e2so ) return;
+
+				assert((e1->type != nullptr) ^ (e1->expr != nullptr));
+				assert((e2so->type != nullptr) ^ (e2so->expr != nullptr));
+				if ( ! (e1->type && e2so->type) )  return;
+
+				// expression unification calls type unification (mutual recursion)
+				result = unifyExact( e1->type, e2so->type, tenv, need, have, open, widen );
+			}
+		}
+
+		UnifyExpr( const ast::Expr * e2, ast::TypeEnvironment & env, ast::AssertionSet & need,
+			ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
+		: e2( e2 ), tenv(env), need(need), have(have), open(open), widen(widen), result(false) {}
+	};
+
+	static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
+		ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
+		WidenMode widen ) {
+		assert( e1 && e2 );
+		return ast::Pass<UnifyExpr>::read( e1, e2, env, need, have, open, widen );
+	}
+
 	class Unify_new final : public ast::WithShortCircuiting {
 		const ast::Type * type2;
@@ -820,16 +942,12 @@
 			if ( ! array2 ) return;
 
-			// to unify, array types must both be VLA or both not VLA and both must have a
-			// dimension expression or not have a dimension
 			if ( array->isVarLen != array2->isVarLen ) return;
-			if ( ! array->isVarLen && ! array2->isVarLen
-					&& array->dimension && array2->dimension ) {
-				auto ce1 = array->dimension.as< ast::ConstantExpr >();
-				auto ce2 = array2->dimension.as< ast::ConstantExpr >();
-
-				// see C11 Reference Manual 6.7.6.2.6
-				// two array types with size specifiers that are integer constant expressions are
-				// compatible if both size specifiers have the same constant value
-				if ( ce1 && ce2 && ce1->intValue() != ce2->intValue() ) return;
+			if ( (array->dimension != nullptr) != (array2->dimension != nullptr) ) return;
+
+			if ( array->dimension ) {
+				assert( array2->dimension );
+				// type unification calls expression unification (mutual recursion)
+				if ( ! unify(array->dimension, array2->dimension,
+				    tenv, need, have, open, widen) ) return;
 			}
 
@@ -1180,23 +1298,7 @@
 		auto var1 = dynamic_cast< const ast::TypeInstType * >( type1 );
 		auto var2 = dynamic_cast< const ast::TypeInstType * >( type2 );
-		ast::OpenVarSet::const_iterator
-			entry1 = var1 ? open.find( *var1 ) : open.end(),
-			entry2 = var2 ? open.find( *var2 ) : open.end();
-		// bool isopen1 = entry1 != open.end();
-		// bool isopen2 = entry2 != open.end();
 		bool isopen1 = var1 && env.lookup(*var1);
 		bool isopen2 = var2 && env.lookup(*var2);
 
-		/*
-		if ( isopen1 && isopen2 ) {
-			if ( entry1->second.kind != entry2->second.kind ) return false;
-			return env.bindVarToVar(
-				var1, var2, ast::TypeData{ entry1->second, entry2->second }, need, have,
-				open, widen );
-		} else if ( isopen1 ) {
-			return env.bindVar( var1, type2, entry1->second, need, have, open, widen );
-		} else if ( isopen2 ) {
-			return env.bindVar( var2, type1, entry2->second, need, have, open, widen, symtab );
-		} */
 		if ( isopen1 && isopen2 ) {
 			if ( var1->base->kind != var2->base->kind ) return false;
@@ -1208,9 +1310,8 @@
 		} else if ( isopen2 ) {
 			return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen );
-		}else {
+		} else {
 			return ast::Pass<Unify_new>::read(
 				type1, type2, env, need, have, open, widen );
 		}
-		
 	}
 
