Index: src/AST/Util.cpp
===================================================================
--- src/AST/Util.cpp	(revision c1e66d966aadf6846330871033458d4a398bd576)
+++ src/AST/Util.cpp	(revision deda7e6002cc711be5c0af09984cec24300d5990)
@@ -104,4 +104,13 @@
 	}
 	assertf( false, "Member not found." );
+}
+
+template<typename node_t>
+void oneOfExprOrType( const node_t * node ) {
+	if ( node->expr ) {
+		assertf( node->expr && !node->type, "Exactly one of expr or type should be set." );
+	} else {
+		assertf( !node->expr && node->type, "Exactly one of expr or type should be set." );
+	}
 }
 
@@ -152,4 +161,14 @@
 	}
 
+	void previsit( const SizeofExpr * node ) {
+		previsit( (const ParseNode *)node );
+		oneOfExprOrType( node );
+	}
+
+	void previsit( const AlignofExpr * node ) {
+		previsit( (const ParseNode *)node );
+		oneOfExprOrType( node );
+	}
+
 	void previsit( const StructInstType * node ) {
 		previsit( (const Node *)node );
@@ -181,4 +200,6 @@
 /// referring to is in scope by the structural rules of code.
 // Any escapes marked with a bug should be removed once the bug is fixed.
+// This is a separate pass because of it changes the visit pattern and
+// must always be run on the entire translation unit.
 struct InScopeCore : public ast::WithShortCircuiting {
 	ScopedSet<DeclWithType const *> typedDecls;
Index: src/ControlStruct/MultiLevelExit.cpp
===================================================================
--- src/ControlStruct/MultiLevelExit.cpp	(revision c1e66d966aadf6846330871033458d4a398bd576)
+++ src/ControlStruct/MultiLevelExit.cpp	(revision deda7e6002cc711be5c0af09984cec24300d5990)
@@ -10,6 +10,6 @@
 // Created On       : Mon Nov  1 13:48:00 2021
 // Last Modified By : Andrew Beach
-// Last Modified On : Wed Sep  6 12:00:00 2023
-// Update Count     : 35
+// Last Modified On : Fri Sep  8 17:04:00 2023
+// Update Count     : 36
 //
 
@@ -27,4 +27,14 @@
 
 namespace {
+
+/// The return context is used to remember if returns are allowed and if
+/// not, why not. It is the nearest local control flow blocking construct.
+enum ReturnContext {
+	MayReturn,
+	InTryWithHandler,
+	InResumeHandler,
+	InTerminateHandler,
+	InFinally,
+};
 
 class Entry {
@@ -126,4 +136,5 @@
 	void previsit( const TryStmt * );
 	void postvisit( const TryStmt * );
+	void previsit( const CatchClause * );
 	void previsit( const FinallyClause * );
 
@@ -134,5 +145,5 @@
 	vector<Entry> enclosing_control_structures;
 	Label break_label;
-	bool inFinally;
+	ReturnContext ret_context;
 
 	template<typename LoopNode>
@@ -144,4 +155,6 @@
 		const list<ptr<Stmt>> & kids, bool caseClause );
 
+	void enterSealedContext( ReturnContext );
+
 	template<typename UnaryPredicate>
 	auto findEnclosingControlStructure( UnaryPredicate pred ) {
@@ -157,5 +170,5 @@
 MultiLevelExitCore::MultiLevelExitCore( const LabelToStmt & lt ) :
 	target_table( lt ), break_label( CodeLocation(), "" ),
-	inFinally( false )
+	ret_context( ReturnContext::MayReturn )
 {}
 
@@ -488,7 +501,24 @@
 
 void MultiLevelExitCore::previsit( const ReturnStmt * stmt ) {
-	if ( inFinally ) {
-		SemanticError( stmt->location, "'return' may not appear in a finally clause" );
-	}
+	char const * context;
+	switch ( ret_context ) {
+	case ReturnContext::MayReturn:
+		return;
+	case ReturnContext::InTryWithHandler:
+		context = "try statement with a catch clause";
+		break;
+	case ReturnContext::InResumeHandler:
+		context = "catchResume clause";
+		break;
+	case ReturnContext::InTerminateHandler:
+		context = "catch clause";
+		break;
+	case ReturnContext::InFinally:
+		context = "finally clause";
+		break;
+	default:
+		assert(0);
+	}
+	SemanticError( stmt->location, toString( "'return' may not appear in a ", context ) );
 }
 
@@ -500,4 +530,11 @@
 		GuardAction([this](){ enclosing_control_structures.pop_back(); } );
 	}
+
+	// Try statements/try blocks are only sealed with a termination handler.
+	for ( auto clause : stmt->handlers ) {
+		if ( ast::Terminate == clause->kind ) {
+			return enterSealedContext( ReturnContext::InTryWithHandler );
+		}
+	}
 }
 
@@ -512,8 +549,12 @@
 }
 
+void MultiLevelExitCore::previsit( const CatchClause * clause ) {
+	ReturnContext context = ( ast::Terminate == clause->kind )
+		? ReturnContext::InTerminateHandler : ReturnContext::InResumeHandler;
+	enterSealedContext( context );
+}
+
 void MultiLevelExitCore::previsit( const FinallyClause * ) {
-	GuardAction([this, old = std::move( enclosing_control_structures)](){ enclosing_control_structures = std::move(old); });
-	enclosing_control_structures = vector<Entry>();
-	GuardValue( inFinally ) = true;
+	enterSealedContext( ReturnContext::InFinally );
 }
 
@@ -617,4 +658,10 @@
 }
 
+void MultiLevelExitCore::enterSealedContext( ReturnContext enter_context ) {
+	GuardAction([this, old = std::move(enclosing_control_structures)](){ enclosing_control_structures = std::move(old); });
+	enclosing_control_structures = vector<Entry>();
+	GuardValue( ret_context ) = enter_context;
+}
+
 } // namespace
 
Index: src/GenPoly/GenPoly.cc
===================================================================
--- src/GenPoly/GenPoly.cc	(revision c1e66d966aadf6846330871033458d4a398bd576)
+++ src/GenPoly/GenPoly.cc	(revision deda7e6002cc711be5c0af09984cec24300d5990)
@@ -48,8 +48,9 @@
 		}
 
-		bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const ast::TypeSubstitution * env) {
-			for (auto &param : params) {
-				auto paramType = param.strict_as<ast::TypeExpr>();
-				if (isPolyType(paramType->type, env)) return true;
+		bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const ast::TypeSubstitution * env ) {
+			for ( auto &param : params ) {
+				auto paramType = param.as<ast::TypeExpr>();
+				assertf( paramType, "Aggregate parameters should be type expressions" );
+				if ( isPolyType( paramType->type, env ) ) return true;
 			}
 			return false;
@@ -62,4 +63,13 @@
 				assertf(paramType, "Aggregate parameters should be type expressions");
 				if ( isPolyType( paramType->get_type(), tyVars, env ) ) return true;
+			}
+			return false;
+		}
+
+		bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const TypeVarMap & typeVars, const ast::TypeSubstitution * env ) {
+			for ( auto & param : params ) {
+				auto paramType = param.as<ast::TypeExpr>();
+				assertf( paramType, "Aggregate parameters should be type expressions" );
+				if ( isPolyType( paramType->type, typeVars, env ) ) return true;
 			}
 			return false;
@@ -185,19 +195,4 @@
 	}
 
-	const ast::Type * isPolyType(const ast::Type * type, const TyVarMap & tyVars, const ast::TypeSubstitution * env) {
-		type = replaceTypeInst( type, env );
-
-		if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( type ) ) {
-			if ( tyVars.contains( typeInst->typeString() ) ) return type;
-		} else if ( auto arrayType = dynamic_cast< const ast::ArrayType * >( type ) ) {
-			return isPolyType( arrayType->base, env );
-		} else if ( auto structType = dynamic_cast< const ast::StructInstType* >( type ) ) {
-			if ( hasPolyParams( structType->params, env ) ) return type;
-		} else if ( auto unionType = dynamic_cast< const ast::UnionInstType* >( type ) ) {
-			if ( hasPolyParams( unionType->params, env ) ) return type;
-		}
-		return nullptr;
-	}
-
 const ast::Type * isPolyType( const ast::Type * type,
 		const TypeVarMap & typeVars, const ast::TypeSubstitution * subst ) {
@@ -207,9 +202,9 @@
 		if ( typeVars.contains( *inst ) ) return type;
 	} else if ( auto array = dynamic_cast< const ast::ArrayType * >( type ) ) {
-		return isPolyType( array->base, subst );
+		return isPolyType( array->base, typeVars, subst );
 	} else if ( auto sue = dynamic_cast< const ast::StructInstType * >( type ) ) {
-		if ( hasPolyParams( sue->params, subst ) ) return type;
+		if ( hasPolyParams( sue->params, typeVars, subst ) ) return type;
 	} else if ( auto sue = dynamic_cast< const ast::UnionInstType * >( type ) ) {
-		if ( hasPolyParams( sue->params, subst ) ) return type;
+		if ( hasPolyParams( sue->params, typeVars, subst ) ) return type;
 	}
 	return nullptr;
