@@ -153,7 +153,22 @@ private bool TryResolveRank([NotNullWhen(true)] out SmtFunctionRank? rank, SmtFu
153153 }
154154 else
155155 {
156- resolvedParameters . Add ( templateSort , concreteSort ) ;
156+ // Template sorts (that are a parameter) are allowed to have arity 0.
157+ // The whole template will just be matched with the concrete sort.
158+ // Otherwise, we want to make sure the arities match.
159+ if ( ! ( templateSort . IsSortParameter && templateSort . Arity == 0 )
160+ && templateSort . Arity != concreteSort . Arity )
161+ {
162+ rank = default ;
163+ return false ;
164+ }
165+
166+ // Recursively match the template and match parameter sorts
167+ if ( ! TraverseAndMatchTemplate ( templateSort , concreteSort , resolvedParameters ) )
168+ {
169+ rank = default ;
170+ return false ;
171+ }
157172 templateSort = concreteSort ;
158173 }
159174 }
@@ -212,6 +227,62 @@ private bool TryResolveRank([NotNullWhen(true)] out SmtFunctionRank? rank, SmtFu
212227 return template . Validator ( rank ) ;
213228 }
214229
230+ /// <summary>
231+ /// Match a template sort and parameters against a concrete sort
232+ /// </summary>
233+ /// <param name="template">Template sort to match</param>
234+ /// <param name="concrete">Concrete sort to match against</param>
235+ /// <param name="resolvedParameters">Dictionary of resolved parameters</param>
236+ /// <returns>True if successfully resolves, false if not</returns>
237+ private static bool TraverseAndMatchTemplate ( SmtSort template , SmtSort concrete , IDictionary < SmtSort , SmtSort > resolvedParameters )
238+ {
239+ // Template can be a parameter, and concrete can be whatever
240+ if ( template . IsSortParameter )
241+ {
242+ if ( resolvedParameters . TryGetValue ( template , out var resolved ) )
243+ {
244+ if ( resolved != concrete )
245+ {
246+ return false ;
247+ }
248+ }
249+ else
250+ {
251+ resolvedParameters . Add ( template , concrete ) ;
252+ }
253+
254+ if ( template . Arity == 0 && concrete . Arity > 0 )
255+ {
256+ return true ;
257+ }
258+ }
259+
260+ // Otherwise, arities must match, so we can traverse
261+ if ( template . Arity != concrete . Arity )
262+ {
263+ return false ;
264+ }
265+
266+ if ( template . IsSortParameter )
267+ {
268+ foreach ( var ( tempParam , concParam ) in template . Parameters . Zip ( concrete . Parameters ) )
269+ {
270+ if ( ! TraverseAndMatchTemplate ( tempParam , concParam , resolvedParameters ) )
271+ {
272+ return false ;
273+ }
274+ }
275+ }
276+ else
277+ {
278+ if ( template != concrete )
279+ {
280+ return false ;
281+ }
282+ }
283+ return true ;
284+ }
285+
215286 /// <summary>
216287 /// Returns a string describing available ranks
217288 /// </summary>
0 commit comments