Index: src/GenPoly/GenPoly.cpp
===================================================================
--- src/GenPoly/GenPoly.cpp	(revision 1a2ba849a94c2cd2e0184e92b6b3241c9dbd3022)
+++ src/GenPoly/GenPoly.cpp	(revision f9ad69dc6e86c3c08876734b6909ce8978446504)
@@ -27,4 +27,5 @@
 #include "AST/Type.hpp"
 #include "AST/TypeSubstitution.hpp"
+#include "Common/Eval.hpp"                // for eval
 #include "GenPoly/ErasableScopedMap.hpp"  // for ErasableScopedMap<>::const_...
 #include "ResolvExpr/Typeops.hpp"         // for flatten
@@ -243,4 +244,72 @@
 } // namespace
 
+// This function, and its helpers following, have logic duplicated from
+// unification.  The difference in context is that unification applies where
+// the types "must" match, while this variation applies to arbitrary type
+// pairs, when an optimization could apply if they happen to match.  This
+// variation does not bind type variables.  The helper functions support
+// the case for matching ArrayType.
+bool typesPolyCompatible( ast::Type const * lhs, ast::Type const * rhs );
+
+static bool exprsPolyCompatibleByStaticValue(
+		const ast::Expr * e1, const ast::Expr * e2 ) {
+	Evaluation r1 = eval(e1);
+	Evaluation r2 = eval(e2);
+
+	if ( !r1.hasKnownValue ) return false;
+	if ( !r2.hasKnownValue ) return false;
+
+	if ( r1.knownValue != r2.knownValue ) return false;
+
+	return true;
+}
+
+static bool exprsPolyCompatible( ast::Expr const * lhs,
+		ast::Expr const * rhs ) {
+	type_index const lid = typeid(*lhs);
+	type_index const rid = typeid(*rhs);
+	if ( lid != rid ) return false;
+
+	if ( exprsPolyCompatibleByStaticValue( lhs, rhs ) ) return true;
+
+	if ( type_index(typeid(ast::CastExpr)) == lid ) {
+		ast::CastExpr const * l = as<ast::CastExpr>(lhs);
+		ast::CastExpr const * r = as<ast::CastExpr>(rhs);
+
+		// inspect casts' target types
+		if ( !typesPolyCompatible(
+			l->result, r->result ) ) return false;
+
+		// inspect casts' inner expressions
+		return exprsPolyCompatible( l->arg, r->arg );
+
+	} else if ( type_index(typeid(ast::VariableExpr)) == lid ) {
+		ast::VariableExpr const * l = as<ast::VariableExpr>(lhs);
+		ast::VariableExpr const * r = as<ast::VariableExpr>(rhs);
+
+		assert(l->var);
+		assert(r->var);
+
+		// conservative: variable exprs match if their declarations are
+		// represented by the same C++ AST object
+		return (l->var == r->var);
+
+	} else if ( type_index(typeid(ast::SizeofExpr)) == lid ) {
+		ast::SizeofExpr const * l = as<ast::SizeofExpr>(lhs);
+		ast::SizeofExpr const * r = as<ast::SizeofExpr>(rhs);
+
+		assert((l->type != nullptr) ^ (l->expr != nullptr));
+		assert((r->type != nullptr) ^ (r->expr != nullptr));
+		if ( !(l->type && r->type) ) return false;
+
+		// mutual recursion with type poly compatibility
+		return typesPolyCompatible( l->type, r->type );
+
+	} else {
+		// All other forms compare on static value only, done earlier
+		return false;
+	}
+}
+
 bool typesPolyCompatible( ast::Type const * lhs, ast::Type const * rhs ) {
 	type_index const lid = typeid(*lhs);
@@ -256,5 +325,5 @@
 
 	// So remaining types can be examined case by case.
-	// Recurse through type structure (conditions borrowed from Unify.cpp).
+	// Recurse through type structure (conditions duplicated from Unify.cpp).
 
 	if ( type_index(typeid(ast::BasicType)) == lid ) {
@@ -280,14 +349,13 @@
 		ast::ArrayType const * r = as<ast::ArrayType>(rhs);
 
-		if ( l->isVarLen ) {
-			if ( !r->isVarLen ) return false;
-		} else {
-			if ( r->isVarLen ) return false;
-
-			auto lc = l->dimension.as<ast::ConstantExpr>();
-			auto rc = r->dimension.as<ast::ConstantExpr>();
-			if ( lc && rc && lc->intValue() != rc->intValue() ) {
+		if ( l->isVarLen != r->isVarLen ) return false;
+		if ( (l->dimension != nullptr) != (r->dimension != nullptr) )
+			return false;
+
+		if ( l->dimension ) {
+			assert( r->dimension );
+			// mutual recursion with expression poly compatibility
+			if ( !exprsPolyCompatible(l->dimension, r->dimension) )
 				return false;
-			}
 		}
 
Index: tests/.expect/poly-many-arsz.txt
===================================================================
--- tests/.expect/poly-many-arsz.txt	(revision f9ad69dc6e86c3c08876734b6909ce8978446504)
+++ tests/.expect/poly-many-arsz.txt	(revision f9ad69dc6e86c3c08876734b6909ce8978446504)
@@ -0,0 +1,9 @@
+baseline
+|y| = 3
+y.second = 0
+y.second = 0
+with interference
+|x| = 2
+|y| = 3
+y.second = 0
+y.second = 0
Index: tests/poly-many-arsz.cfa
===================================================================
--- tests/poly-many-arsz.cfa	(revision f9ad69dc6e86c3c08876734b6909ce8978446504)
+++ tests/poly-many-arsz.cfa	(revision f9ad69dc6e86c3c08876734b6909ce8978446504)
@@ -0,0 +1,63 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2023 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// poly-many-arsz.cfa -- using many built-in array types with concrete sizes
+//
+// Author           : Mike Brooks
+// Created On       : Tue Aug 13 12:00:00 2024
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+// This behaviour was once broken, as trac #175.
+
+forall( T1*, T2* )
+struct mypair {
+    T1 first;
+    T2 second;
+};
+
+void baseline( void ) {
+    printf("baseline\n");
+
+    // no declaration of x
+    // facts that are true of y:
+
+    mypair(char[2], char) y @= {};
+    printf("|y| = %ld\n", sizeof(y));    // 3
+
+    y.second = 0;
+    printf("y.second = %d\n", y.second); // 0
+
+    y.first[1] = 17;
+    printf("y.second = %d\n", y.second); // 0
+}
+
+void withInterference( void ) {
+    printf("with interference\n");
+
+    // adding this declaration of x ...
+    mypair(char[1], char) x @= {};
+    printf("|x| = %ld\n", sizeof(x));    // 2
+
+    // ... must not affect the observed facts of y:
+
+    mypair(char[2], char) y @= {};
+    printf("|y| = %ld\n", sizeof(y));    // 3
+
+    y.second = 0;
+    printf("y.second = %d\n", y.second); // 0
+
+    y.first[1] = 17;
+    printf("y.second = %d\n", y.second); // 0
+}
+
+int main() {
+    baseline();
+    withInterference();
+    return 0;
+}
