source: src/ResolvExpr/Unify.cc @ e6e1a12

Last change on this file since e6e1a12 was f02f546, checked in by Michael Brooks <mlbrooks@…>, 18 months ago

Implement new rules for array dimension expression matching.

Core changes:
src/ResolvExpr/Unify.cc: add sense of "these two expressions unify"
src/InitTweak/GenInit.cc: make hoisting happen more often
tests/array-container/*: reconfigure the array-dimension test to use non-"classic" expectation rules

Misc contributors and noise:
libcfa/src/parseargs.cfa: ,ake a parameter, that's used as a length expression, constant (example of an array user following new rules)
src/ResolvExpr/ResolveTypeof.h: make fixArrayType public
src/Validate/GenericParameter.cpp: do the array-type desugaring in both AST corners that forall-variables can be found (not just in one of them)
tests/.expect/typedefRedef-ERR1.txt: old one was "expecting" a bug, that new array rules handle correctly

  • Property mode set to 100644
File size: 52.4 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// Unify.cc --
8//
9// Author           : Richard C. Bilson
10// Created On       : Sun May 17 12:27:10 2015
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Fri Dec 13 23:43:05 2019
13// Update Count     : 46
14//
15
16#include "Unify.h"
17
18#include <cassert>                  // for assertf, assert
19#include <iterator>                 // for back_insert_iterator, back_inserter
20#include <map>                      // for _Rb_tree_const_iterator, _Rb_tree_i...
21#include <memory>                   // for unique_ptr
22#include <set>                      // for set
23#include <string>                   // for string, operator==, operator!=, bas...
24#include <utility>                  // for pair, move
25#include <vector>
26
27#include "AST/Copy.hpp"
28#include "AST/Decl.hpp"
29#include "AST/Node.hpp"
30#include "AST/Pass.hpp"
31#include "AST/Print.hpp"
32#include "AST/Type.hpp"
33#include "AST/TypeEnvironment.hpp"
34#include "Common/Eval.h"            // for eval
35#include "Common/PassVisitor.h"     // for PassVisitor
36#include "CommonType.hpp"           // for commonType
37#include "FindOpenVars.h"           // for findOpenVars
38#include "SpecCost.hpp"             // for SpecCost
39#include "SynTree/LinkageSpec.h"    // for C
40#include "SynTree/Constant.h"       // for Constant
41#include "SynTree/Declaration.h"    // for TypeDecl, TypeDecl::Data, Declarati...
42#include "SynTree/Expression.h"     // for TypeExpr, Expression, ConstantExpr
43#include "SynTree/Mutator.h"        // for Mutator
44#include "SynTree/Type.h"           // for Type, TypeInstType, FunctionType
45#include "SynTree/Visitor.h"        // for Visitor
46#include "Tuples/Tuples.h"          // for isTtype
47#include "TypeEnvironment.h"        // for EqvClass, AssertionSet, OpenVarSet
48#include "typeops.h"                // for flatten, occurs
49
50namespace ast {
51        class SymbolTable;
52}
53
54namespace SymTab {
55        class Indexer;
56}  // namespace SymTab
57
58// #define DEBUG
59
60namespace ResolvExpr {
61
62// Template Helpers:
63template< typename Iterator1, typename Iterator2 >
64bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, std::list< Type* > &commonTypes ) {
65        for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
66                Type *commonType = 0;
67                if ( ! unify( *list1Begin, *list2Begin, env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
68                        return false;
69                } // if
70                commonTypes.push_back( commonType );
71        } // for
72        return ( list1Begin == list1End && list2Begin == list2End );
73}
74
75template< typename Iterator1, typename Iterator2 >
76bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
77        std::list< Type* > commonTypes;
78        if ( unifyList( list1Begin, list1End, list2Begin, list2End, env, needAssertions, haveAssertions,  openVars, indexer, commonTypes ) ) {
79                deleteAll( commonTypes );
80                return true;
81        } else {
82                return false;
83        } // if
84}
85
86        struct Unify_old : public WithShortCircuiting {
87                Unify_old( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );
88
89                bool get_result() const { return result; }
90
91                void previsit( BaseSyntaxNode * ) { visit_children = false; }
92
93                void postvisit( VoidType * voidType );
94                void postvisit( BasicType * basicType );
95                void postvisit( PointerType * pointerType );
96                void postvisit( ArrayType * arrayType );
97                void postvisit( ReferenceType * refType );
98                void postvisit( FunctionType * functionType );
99                void postvisit( StructInstType * aggregateUseType );
100                void postvisit( UnionInstType * aggregateUseType );
101                void postvisit( EnumInstType * aggregateUseType );
102                void postvisit( TraitInstType * aggregateUseType );
103                void postvisit( TypeInstType * aggregateUseType );
104                void postvisit( TupleType * tupleType );
105                void postvisit( VarArgsType * varArgsType );
106                void postvisit( ZeroType * zeroType );
107                void postvisit( OneType * oneType );
108
109          private:
110                template< typename RefType > void handleRefType( RefType *inst, Type *other );
111                template< typename RefType > void handleGenericRefType( RefType *inst, Type *other );
112
113                bool result;
114                Type *type2;                            // inherited
115                TypeEnvironment &env;
116                AssertionSet &needAssertions;
117                AssertionSet &haveAssertions;
118                const OpenVarSet &openVars;
119                WidenMode widen;
120                const SymTab::Indexer &indexer;
121        };
122
123        /// Attempts an inexact unification of type1 and type2.
124        /// Returns false if no such unification; if the types can be unified, sets common (unless they unify exactly and have identical type qualifiers)
125        bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common );
126        bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );
127
128        bool unifyExact(
129                const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
130                ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
131                WidenMode widen );
132
133        bool typesCompatible( const Type * first, const Type * second, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
134                TypeEnvironment newEnv;
135                OpenVarSet openVars, closedVars; // added closedVars
136                AssertionSet needAssertions, haveAssertions;
137                Type * newFirst = first->clone(), * newSecond = second->clone();
138                env.apply( newFirst );
139                env.apply( newSecond );
140
141                // do we need to do this? Seems like we do, types should be able to be compatible if they
142                // have free variables that can unify
143                findOpenVars( newFirst, openVars, closedVars, needAssertions, haveAssertions, false );
144                findOpenVars( newSecond, openVars, closedVars, needAssertions, haveAssertions, true );
145
146                bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
147                delete newFirst;
148                delete newSecond;
149                return result;
150        }
151
152        bool typesCompatible(
153                        const ast::Type * first, const ast::Type * second,
154                        const ast::TypeEnvironment & env ) {
155                ast::TypeEnvironment newEnv;
156                ast::OpenVarSet open, closed;
157                ast::AssertionSet need, have;
158
159                ast::ptr<ast::Type> newFirst{ first }, newSecond{ second };
160                env.apply( newFirst );
161                env.apply( newSecond );
162
163                // findOpenVars( newFirst, open, closed, need, have, FirstClosed );
164                findOpenVars( newSecond, open, closed, need, have, newEnv, FirstOpen );
165
166                return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden() );
167        }
168
169        bool typesCompatibleIgnoreQualifiers( const Type * first, const Type * second, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
170                TypeEnvironment newEnv;
171                OpenVarSet openVars;
172                AssertionSet needAssertions, haveAssertions;
173                Type *newFirst = first->clone(), *newSecond = second->clone();
174                env.apply( newFirst );
175                env.apply( newSecond );
176                newFirst->get_qualifiers() = Type::Qualifiers();
177                newSecond->get_qualifiers() = Type::Qualifiers();
178
179                bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
180                delete newFirst;
181                delete newSecond;
182                return result;
183        }
184
185        bool typesCompatibleIgnoreQualifiers(
186                        const ast::Type * first, const ast::Type * second,
187                        const ast::TypeEnvironment & env ) {
188                ast::TypeEnvironment newEnv;
189                ast::OpenVarSet open;
190                ast::AssertionSet need, have;
191
192                ast::Type * newFirst  = shallowCopy( first  );
193                ast::Type * newSecond = shallowCopy( second );
194                if ( auto temp = dynamic_cast<const ast::EnumInstType *>(first) ) {
195                        if ( !dynamic_cast< const ast::EnumInstType * >( second ) ) {
196                                const ast::EnumDecl * baseEnum = dynamic_cast<const ast::EnumDecl *>(temp->base.get());
197                                if ( auto t = baseEnum->base.get() ) {
198                                        newFirst = ast::shallowCopy( t );
199                                }
200                        }
201                } else if ( auto temp = dynamic_cast<const ast::EnumInstType *>(second) ) {
202                        const ast::EnumDecl * baseEnum = dynamic_cast<const ast::EnumDecl *>(temp->base.get());
203                        if ( auto t = baseEnum->base.get() ) {
204                                newSecond = ast::shallowCopy( t );
205                        }
206                }
207
208                newFirst ->qualifiers = {};
209                newSecond->qualifiers = {};
210                ast::ptr< ast::Type > t1_(newFirst );
211                ast::ptr< ast::Type > t2_(newSecond);
212
213                ast::ptr< ast::Type > subFirst = env.apply(newFirst).node;
214                ast::ptr< ast::Type > subSecond = env.apply(newSecond).node;
215
216                return unifyExact(
217                        subFirst,
218                        subSecond,
219                        newEnv, need, have, open, noWiden() );
220        }
221
222        bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
223                OpenVarSet closedVars;
224                findOpenVars( type1, openVars, closedVars, needAssertions, haveAssertions, false );
225                findOpenVars( type2, openVars, closedVars, needAssertions, haveAssertions, true );
226                Type *commonType = 0;
227                if ( unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( true, true ), indexer, commonType ) ) {
228                        if ( commonType ) {
229                                delete commonType;
230                        } // if
231                        return true;
232                } else {
233                        return false;
234                } // if
235        }
236
237        bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType ) {
238                OpenVarSet closedVars;
239                findOpenVars( type1, openVars, closedVars, needAssertions, haveAssertions, false );
240                findOpenVars( type2, openVars, closedVars, needAssertions, haveAssertions, true );
241                return unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( true, true ), indexer, commonType );
242        }
243
244        bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ) {
245#ifdef DEBUG
246                TypeEnvironment debugEnv( env );
247#endif
248                if ( type1->get_qualifiers() != type2->get_qualifiers() ) {
249                        return false;
250                }
251
252                bool result;
253                TypeInstType *var1 = dynamic_cast< TypeInstType* >( type1 );
254                TypeInstType *var2 = dynamic_cast< TypeInstType* >( type2 );
255                OpenVarSet::const_iterator entry1, entry2;
256                if ( var1 ) {
257                        entry1 = openVars.find( var1->get_name() );
258                } // if
259                if ( var2 ) {
260                        entry2 = openVars.find( var2->get_name() );
261                } // if
262                bool isopen1 = var1 && ( entry1 != openVars.end() );
263                bool isopen2 = var2 && ( entry2 != openVars.end() );
264
265                if ( isopen1 && isopen2 ) {
266                        if ( entry1->second.kind != entry2->second.kind ) {
267                                result = false;
268                        } else {
269                                result = env.bindVarToVar(
270                                        var1, var2, TypeDecl::Data{ entry1->second, entry2->second }, needAssertions,
271                                        haveAssertions, openVars, widen, indexer );
272                        }
273                } else if ( isopen1 ) {
274                        result = env.bindVar( var1, type2, entry1->second, needAssertions, haveAssertions, openVars, widen, indexer );
275                } else if ( isopen2 ) { // TODO: swap widen values in call, since type positions are flipped?
276                        result = env.bindVar( var2, type1, entry2->second, needAssertions, haveAssertions, openVars, widen, indexer );
277                } else {
278                        PassVisitor<Unify_old> comparator( type2, env, needAssertions, haveAssertions, openVars, widen, indexer );
279                        type1->accept( comparator );
280                        result = comparator.pass.get_result();
281                } // if
282#ifdef DEBUG
283                std::cerr << "============ unifyExact" << std::endl;
284                std::cerr << "type1 is ";
285                type1->print( std::cerr );
286                std::cerr << std::endl << "type2 is ";
287                type2->print( std::cerr );
288                std::cerr << std::endl << "openVars are ";
289                printOpenVarSet( openVars, std::cerr, 8 );
290                std::cerr << std::endl << "input env is " << std::endl;
291                debugEnv.print( std::cerr, 8 );
292                std::cerr << std::endl << "result env is " << std::endl;
293                env.print( std::cerr, 8 );
294                std::cerr << "result is " << result << std::endl;
295#endif
296                return result;
297        }
298
299        bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
300                return unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
301        }
302
303        bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common ) {
304                Type::Qualifiers tq1 = type1->get_qualifiers(), tq2 = type2->get_qualifiers();
305                type1->get_qualifiers() = Type::Qualifiers();
306                type2->get_qualifiers() = Type::Qualifiers();
307                bool result;
308#ifdef DEBUG
309                std::cerr << "unifyInexact type 1 is ";
310                type1->print( std::cerr );
311                std::cerr << " type 2 is ";
312                type2->print( std::cerr );
313                std::cerr << std::endl;
314#endif
315                if ( ! unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, widen, indexer ) ) {
316#ifdef DEBUG
317                        std::cerr << "unifyInexact: no exact unification found" << std::endl;
318#endif
319                        if ( ( common = commonType( type1, type2, widen.first, widen.second, indexer, env, openVars ) ) ) {
320                                common->tq = tq1.unify( tq2 );
321#ifdef DEBUG
322                                std::cerr << "unifyInexact: common type is ";
323                                common->print( std::cerr );
324                                std::cerr << std::endl;
325#endif
326                                result = true;
327                        } else {
328#ifdef DEBUG
329                                std::cerr << "unifyInexact: no common type found" << std::endl;
330#endif
331                                result = false;
332                        } // if
333                } else {
334                        if ( tq1 != tq2 ) {
335                                if ( ( tq1 > tq2 || widen.first ) && ( tq2 > tq1 || widen.second ) ) {
336                                        common = type1->clone();
337                                        common->tq = tq1.unify( tq2 );
338                                        result = true;
339                                } else {
340                                        result = false;
341                                } // if
342                        } else {
343                                common = type1->clone();
344                                common->tq = tq1.unify( tq2 );
345                                result = true;
346                        } // if
347                } // if
348                type1->get_qualifiers() = tq1;
349                type2->get_qualifiers() = tq2;
350                return result;
351        }
352
353        Unify_old::Unify_old( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer )
354                : result( false ), type2( type2 ), env( env ), needAssertions( needAssertions ), haveAssertions( haveAssertions ), openVars( openVars ), widen( widen ), indexer( indexer ) {
355        }
356
357        void Unify_old::postvisit( __attribute__((unused)) VoidType *voidType) {
358                result = dynamic_cast< VoidType* >( type2 );
359        }
360
361        void Unify_old::postvisit(BasicType *basicType) {
362                if ( BasicType *otherBasic = dynamic_cast< BasicType* >( type2 ) ) {
363                        result = basicType->get_kind() == otherBasic->get_kind();
364                } // if
365        }
366
367        void markAssertionSet( AssertionSet &assertions, DeclarationWithType *assert ) {
368                AssertionSet::iterator i = assertions.find( assert );
369                if ( i != assertions.end() ) {
370                        i->second.isUsed = true;
371                } // if
372        }
373
374        void markAssertions( AssertionSet &assertion1, AssertionSet &assertion2, Type *type ) {
375                for ( std::list< TypeDecl* >::const_iterator tyvar = type->get_forall().begin(); tyvar != type->get_forall().end(); ++tyvar ) {
376                        for ( std::list< DeclarationWithType* >::const_iterator assert = (*tyvar)->get_assertions().begin(); assert != (*tyvar)->get_assertions().end(); ++assert ) {
377                                markAssertionSet( assertion1, *assert );
378                                markAssertionSet( assertion2, *assert );
379                        } // for
380                } // for
381        }
382
383        void Unify_old::postvisit(PointerType *pointerType) {
384                if ( PointerType *otherPointer = dynamic_cast< PointerType* >( type2 ) ) {
385                        result = unifyExact( pointerType->get_base(), otherPointer->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
386                        markAssertions( haveAssertions, needAssertions, pointerType );
387                        markAssertions( haveAssertions, needAssertions, otherPointer );
388                } // if
389        }
390
391        void Unify_old::postvisit(ReferenceType *refType) {
392                if ( ReferenceType *otherRef = dynamic_cast< ReferenceType* >( type2 ) ) {
393                        result = unifyExact( refType->get_base(), otherRef->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
394                        markAssertions( haveAssertions, needAssertions, refType );
395                        markAssertions( haveAssertions, needAssertions, otherRef );
396                } // if
397        }
398
399        void Unify_old::postvisit(ArrayType *arrayType) {
400                ArrayType *otherArray = dynamic_cast< ArrayType* >( type2 );
401                // to unify, array types must both be VLA or both not VLA
402                // and must both have a dimension expression or not have a dimension
403                if ( otherArray && arrayType->get_isVarLen() == otherArray->get_isVarLen() ) {
404
405                        if ( ! arrayType->get_isVarLen() && ! otherArray->get_isVarLen() &&
406                                arrayType->get_dimension() != 0 && otherArray->get_dimension() != 0 ) {
407                                ConstantExpr * ce1 = dynamic_cast< ConstantExpr * >( arrayType->get_dimension() );
408                                ConstantExpr * ce2 = dynamic_cast< ConstantExpr * >( otherArray->get_dimension() );
409                                // see C11 Reference Manual 6.7.6.2.6
410                                // two array types with size specifiers that are integer constant expressions are
411                                // compatible if both size specifiers have the same constant value
412                                if ( ce1 && ce2 ) {
413                                        Constant * c1 = ce1->get_constant();
414                                        Constant * c2 = ce2->get_constant();
415
416                                        if ( c1->get_value() != c2->get_value() ) {
417                                                // does not unify if the dimension is different
418                                                return;
419                                        }
420                                }
421                        }
422
423                        result = unifyExact( arrayType->get_base(), otherArray->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
424                } // if
425        }
426
427        template< typename Iterator, typename Func >
428        std::unique_ptr<Type> combineTypes( Iterator begin, Iterator end, Func & toType ) {
429                std::list< Type * > types;
430                for ( ; begin != end; ++begin ) {
431                        // it's guaranteed that a ttype variable will be bound to a flat tuple, so ensure that this results in a flat tuple
432                        flatten( toType( *begin ), back_inserter( types ) );
433                }
434                return std::unique_ptr<Type>( new TupleType( Type::Qualifiers(), types ) );
435        }
436
437        template< typename Iterator1, typename Iterator2 >
438        bool unifyTypeList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
439                auto get_type = [](DeclarationWithType * dwt){ return dwt->get_type(); };
440                for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
441                        Type * t1 = (*list1Begin)->get_type();
442                        Type * t2 = (*list2Begin)->get_type();
443                        bool isTtype1 = Tuples::isTtype( t1 );
444                        bool isTtype2 = Tuples::isTtype( t2 );
445                        // xxx - assumes ttype must be last parameter
446                        // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases.
447                        if ( isTtype1 && ! isTtype2 ) {
448                                // combine all of the things in list2, then unify
449                                return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
450                        } else if ( isTtype2 && ! isTtype1 ) {
451                                // combine all of the things in list1, then unify
452                                return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
453                        } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {
454                                return false;
455                        } // if
456                } // for
457                // may get to the end of one argument list before the end of the other. This is only okay when the other is a ttype
458                if ( list1Begin != list1End ) {
459                        // try unifying empty tuple type with ttype
460                        Type * t1 = (*list1Begin)->get_type();
461                        if ( Tuples::isTtype( t1 ) ) {
462                                return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
463                        } else return false;
464                } else if ( list2Begin != list2End ) {
465                        // try unifying empty tuple type with ttype
466                        Type * t2 = (*list2Begin)->get_type();
467                        if ( Tuples::isTtype( t2 ) ) {
468                                return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
469                        } else return false;
470                } else {
471                        return true;
472                } // if
473        }
474
475        /// Finds ttypes and replaces them with their expansion, if known.
476        /// This needs to be done so that satisfying ttype assertions is easier.
477        /// If this isn't done then argument lists can have wildly different
478        /// size and structure, when they should be compatible.
479        struct TtypeExpander_old : public WithShortCircuiting {
480                TypeEnvironment & tenv;
481                TtypeExpander_old( TypeEnvironment & tenv ) : tenv( tenv ) {}
482                void premutate( TypeInstType * ) { visit_children = false; }
483                Type * postmutate( TypeInstType * typeInst ) {
484                        if ( const EqvClass *eqvClass = tenv.lookup( typeInst->get_name() ) ) {
485                                // expand ttype parameter into its actual type
486                                if ( eqvClass->data.kind == TypeDecl::Ttype && eqvClass->type ) {
487                                        delete typeInst;
488                                        return eqvClass->type->clone();
489                                }
490                        }
491                        return typeInst;
492                }
493        };
494
495        /// flattens a list of declarations, so that each tuple type has a single declaration.
496        /// makes use of TtypeExpander to ensure ttypes are flat as well.
497        void flattenList( std::list< DeclarationWithType * > src, std::list< DeclarationWithType * > & dst, TypeEnvironment & env ) {
498                dst.clear();
499                for ( DeclarationWithType * dcl : src ) {
500                        PassVisitor<TtypeExpander_old> expander( env );
501                        dcl->acceptMutator( expander );
502                        std::list< Type * > types;
503                        flatten( dcl->get_type(), back_inserter( types ) );
504                        for ( Type * t : types ) {
505                                // outermost const, volatile, _Atomic qualifiers in parameters should not play a role in the unification of function types, since they do not determine whether a function is callable.
506                                // Note: MUST consider at least mutex qualifier, since functions can be overloaded on outermost mutex and a mutex function has different requirements than a non-mutex function.
507                                t->get_qualifiers() -= Type::Qualifiers(Type::Const | Type::Volatile | Type::Atomic);
508
509                                dst.push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::C, nullptr, t, nullptr ) );
510                        }
511                        delete dcl;
512                }
513        }
514
515        void Unify_old::postvisit(FunctionType *functionType) {
516                FunctionType *otherFunction = dynamic_cast< FunctionType* >( type2 );
517                if ( otherFunction && functionType->get_isVarArgs() == otherFunction->get_isVarArgs() ) {
518                        // flatten the parameter lists for both functions so that tuple structure
519                        // doesn't affect unification. Must be a clone so that the types don't change.
520                        std::unique_ptr<FunctionType> flatFunc( functionType->clone() );
521                        std::unique_ptr<FunctionType> flatOther( otherFunction->clone() );
522                        flattenList( flatFunc->get_parameters(), flatFunc->get_parameters(), env );
523                        flattenList( flatOther->get_parameters(), flatOther->get_parameters(), env );
524
525                        // sizes don't have to match if ttypes are involved; need to be more precise wrt where the ttype is to prevent errors
526                        if (
527                                        (flatFunc->parameters.size() == flatOther->parameters.size() &&
528                                                flatFunc->returnVals.size() == flatOther->returnVals.size())
529                                        || flatFunc->isTtype()
530                                        || flatOther->isTtype()
531                        ) {
532                                if ( unifyTypeList( flatFunc->parameters.begin(), flatFunc->parameters.end(), flatOther->parameters.begin(), flatOther->parameters.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
533                                        if ( unifyTypeList( flatFunc->returnVals.begin(), flatFunc->returnVals.end(), flatOther->returnVals.begin(), flatOther->returnVals.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
534
535                                                // the original types must be used in mark assertions, since pointer comparisons are used
536                                                markAssertions( haveAssertions, needAssertions, functionType );
537                                                markAssertions( haveAssertions, needAssertions, otherFunction );
538
539                                                result = true;
540                                        } // if
541                                } // if
542                        } // if
543                } // if
544        }
545
546        template< typename RefType >
547        void Unify_old::handleRefType( RefType *inst, Type *other ) {
548                // check that other type is compatible and named the same
549                RefType *otherStruct = dynamic_cast< RefType* >( other );
550                result = otherStruct && inst->name == otherStruct->name;
551        }
552
553        template< typename RefType >
554        void Unify_old::handleGenericRefType( RefType *inst, Type *other ) {
555                // Check that other type is compatible and named the same
556                handleRefType( inst, other );
557                if ( ! result ) return;
558                // Check that parameters of types unify, if any
559                std::list< Expression* > params = inst->parameters;
560                std::list< Expression* > otherParams = ((RefType*)other)->parameters;
561
562                std::list< Expression* >::const_iterator it = params.begin(), jt = otherParams.begin();
563                for ( ; it != params.end() && jt != otherParams.end(); ++it, ++jt ) {
564                        TypeExpr *param = dynamic_cast< TypeExpr* >(*it);
565                        assertf(param, "Aggregate parameters should be type expressions");
566                        TypeExpr *otherParam = dynamic_cast< TypeExpr* >(*jt);
567                        assertf(otherParam, "Aggregate parameters should be type expressions");
568
569                        Type* paramTy = param->get_type();
570                        Type* otherParamTy = otherParam->get_type();
571
572                        bool tupleParam = Tuples::isTtype( paramTy );
573                        bool otherTupleParam = Tuples::isTtype( otherParamTy );
574
575                        if ( tupleParam && otherTupleParam ) {
576                                ++it; ++jt;  // skip ttype parameters for break
577                        } else if ( tupleParam ) {
578                                // bundle other parameters into tuple to match
579                                std::list< Type * > binderTypes;
580
581                                do {
582                                        binderTypes.push_back( otherParam->get_type()->clone() );
583                                        ++jt;
584
585                                        if ( jt == otherParams.end() ) break;
586
587                                        otherParam = dynamic_cast< TypeExpr* >(*jt);
588                                        assertf(otherParam, "Aggregate parameters should be type expressions");
589                                } while (true);
590
591                                otherParamTy = new TupleType{ paramTy->get_qualifiers(), binderTypes };
592                                ++it;  // skip ttype parameter for break
593                        } else if ( otherTupleParam ) {
594                                // bundle parameters into tuple to match other
595                                std::list< Type * > binderTypes;
596
597                                do {
598                                        binderTypes.push_back( param->get_type()->clone() );
599                                        ++it;
600
601                                        if ( it == params.end() ) break;
602
603                                        param = dynamic_cast< TypeExpr* >(*it);
604                                        assertf(param, "Aggregate parameters should be type expressions");
605                                } while (true);
606
607                                paramTy = new TupleType{ otherParamTy->get_qualifiers(), binderTypes };
608                                ++jt;  // skip ttype parameter for break
609                        }
610
611                        if ( ! unifyExact( paramTy, otherParamTy, env, needAssertions, haveAssertions, openVars, WidenMode(false, false), indexer ) ) {
612                                result = false;
613                                return;
614                        }
615
616                        // ttype parameter should be last
617                        if ( tupleParam || otherTupleParam ) break;
618                }
619                result = ( it == params.end() && jt == otherParams.end() );
620        }
621
622        void Unify_old::postvisit(StructInstType *structInst) {
623                handleGenericRefType( structInst, type2 );
624        }
625
626        void Unify_old::postvisit(UnionInstType *unionInst) {
627                handleGenericRefType( unionInst, type2 );
628        }
629
630        void Unify_old::postvisit(EnumInstType *enumInst) {
631                handleRefType( enumInst, type2 );
632        }
633
634        void Unify_old::postvisit(TraitInstType *contextInst) {
635                handleRefType( contextInst, type2 );
636        }
637
638        void Unify_old::postvisit(TypeInstType *typeInst) {
639                assert( openVars.find( typeInst->get_name() ) == openVars.end() );
640                TypeInstType *otherInst = dynamic_cast< TypeInstType* >( type2 );
641                if ( otherInst && typeInst->get_name() == otherInst->get_name() ) {
642                        result = true;
643///   } else {
644///     NamedTypeDecl *nt = indexer.lookupType( typeInst->get_name() );
645///     if ( nt ) {
646///       TypeDecl *type = dynamic_cast< TypeDecl* >( nt );
647///       assert( type );
648///       if ( type->get_base() ) {
649///         result = unifyExact( type->get_base(), typeInst, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
650///       }
651///     }
652                } // if
653        }
654
655        template< typename Iterator1, typename Iterator2 >
656        bool unifyList( Iterator1 list1Begin, Iterator1 list1End, Iterator2 list2Begin, Iterator2 list2End, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, const SymTab::Indexer &indexer ) {
657                auto get_type = [](Type * t) { return t; };
658                for ( ; list1Begin != list1End && list2Begin != list2End; ++list1Begin, ++list2Begin ) {
659                        Type * t1 = *list1Begin;
660                        Type * t2 = *list2Begin;
661                        bool isTtype1 = Tuples::isTtype( t1 );
662                        bool isTtype2 = Tuples::isTtype( t2 );
663                        // xxx - assumes ttype must be last parameter
664                        // xxx - there may be a nice way to refactor this, but be careful because the argument positioning might matter in some cases.
665                        if ( isTtype1 && ! isTtype2 ) {
666                                // combine all of the things in list2, then unify
667                                return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
668                        } else if ( isTtype2 && ! isTtype1 ) {
669                                // combine all of the things in list1, then unify
670                                return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
671                        } else if ( ! unifyExact( t1, t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ) ) {
672                                return false;
673                        } // if
674
675                } // for
676                if ( list1Begin != list1End ) {
677                        // try unifying empty tuple type with ttype
678                        Type * t1 = *list1Begin;
679                        if ( Tuples::isTtype( t1 ) ) {
680                                return unifyExact( t1, combineTypes( list2Begin, list2End, get_type ).get(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
681                        } else return false;
682                } else if ( list2Begin != list2End ) {
683                        // try unifying empty tuple type with ttype
684                        Type * t2 = *list2Begin;
685                        if ( Tuples::isTtype( t2 ) ) {
686                                return unifyExact( combineTypes( list1Begin, list1End, get_type ).get(), t2, env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
687                        } else return false;
688                } else {
689                        return true;
690                } // if
691        }
692
693        void Unify_old::postvisit(TupleType *tupleType) {
694                if ( TupleType *otherTuple = dynamic_cast< TupleType* >( type2 ) ) {
695                        std::unique_ptr<TupleType> flat1( tupleType->clone() );
696                        std::unique_ptr<TupleType> flat2( otherTuple->clone() );
697                        std::list<Type *> types1, types2;
698
699                        PassVisitor<TtypeExpander_old> expander( env );
700                        flat1->acceptMutator( expander );
701                        flat2->acceptMutator( expander );
702
703                        flatten( flat1.get(), back_inserter( types1 ) );
704                        flatten( flat2.get(), back_inserter( types2 ) );
705
706                        result = unifyList( types1.begin(), types1.end(), types2.begin(), types2.end(), env, needAssertions, haveAssertions, openVars, indexer );
707                } // if
708        }
709
710        void Unify_old::postvisit( __attribute__((unused)) VarArgsType *varArgsType ) {
711                result = dynamic_cast< VarArgsType* >( type2 );
712        }
713
714        void Unify_old::postvisit( __attribute__((unused)) ZeroType *zeroType ) {
715                result = dynamic_cast< ZeroType* >( type2 );
716        }
717
718        void Unify_old::postvisit( __attribute__((unused)) OneType *oneType ) {
719                result = dynamic_cast< OneType* >( type2 );
720        }
721
722        Type * extractResultType( FunctionType * function ) {
723                if ( function->get_returnVals().size() == 0 ) {
724                        return new VoidType( Type::Qualifiers() );
725                } else if ( function->get_returnVals().size() == 1 ) {
726                        return function->get_returnVals().front()->get_type()->clone();
727                } else {
728                        std::list< Type * > types;
729                        for ( DeclarationWithType * decl : function->get_returnVals() ) {
730                                types.push_back( decl->get_type()->clone() );
731                        } // for
732                        return new TupleType( Type::Qualifiers(), types );
733                }
734        }
735
736        namespace {
737                                /// Replaces ttype variables with their bound types.
738                /// If this isn't done when satifying ttype assertions, then argument lists can have
739                /// different size and structure when they should be compatible.
740                struct TtypeExpander_new : public ast::WithShortCircuiting, public ast::PureVisitor {
741                        ast::TypeEnvironment & tenv;
742
743                        TtypeExpander_new( ast::TypeEnvironment & env ) : tenv( env ) {}
744
745                        const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {
746                                if ( const ast::EqvClass * clz = tenv.lookup( *typeInst ) ) {
747                                        // expand ttype parameter into its actual type
748                                        if ( clz->data.kind == ast::TypeDecl::Ttype && clz->bound ) {
749                                                return clz->bound;
750                                        }
751                                }
752                                return typeInst;
753                        }
754                };
755        }
756
757        std::vector< ast::ptr< ast::Type > > flattenList(
758                const std::vector< ast::ptr< ast::Type > > & src, ast::TypeEnvironment & env
759        ) {
760                std::vector< ast::ptr< ast::Type > > dst;
761                dst.reserve( src.size() );
762                for ( const auto & d : src ) {
763                        ast::Pass<TtypeExpander_new> expander{ env };
764                        // TtypeExpander pass is impure (may mutate nodes in place)
765                        // need to make nodes shared to prevent accidental mutation
766                        ast::ptr<ast::Type> dc = d->accept(expander);
767                        auto types = flatten( dc );
768                        for ( ast::ptr< ast::Type > & t : types ) {
769                                // outermost const, volatile, _Atomic qualifiers in parameters should not play
770                                // a role in the unification of function types, since they do not determine
771                                // whether a function is callable.
772                                // NOTE: **must** consider at least mutex qualifier, since functions can be
773                                // overloaded on outermost mutex and a mutex function has different
774                                // requirements than a non-mutex function
775                                remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic );
776                                dst.emplace_back( t );
777                        }
778                }
779                return dst;
780        }
781
782        // Unification of Expressions
783        //
784        // Boolean outcome (obvious):  Are they basically spelled the same?
785        // Side effect of binding variables (subtle):  if `sizeof(int)` ===_expr `sizeof(T)` then `int` ===_ty `T`
786        //
787        // Context:  if `float[VAREXPR1]` ===_ty `float[VAREXPR2]` then `VAREXPR1` ===_expr `VAREXPR2`
788        // where the VAREXPR are meant as notational metavariables representing the fact that unification always
789        // sees distinct ast::VariableExpr objects at these positions
790
791        static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
792                ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
793                WidenMode widen );
794
795        class UnifyExpr final : public ast::WithShortCircuiting {
796                const ast::Expr * e2;
797                ast::TypeEnvironment & tenv;
798                ast::AssertionSet & need;
799                ast::AssertionSet & have;
800                const ast::OpenVarSet & open;
801                WidenMode widen;
802        public:
803                bool result;
804
805        private:
806
807                void tryMatchOnStaticValue( const ast::Expr * e1 ) {
808                        Evaluation r1 = eval(e1);
809                        Evaluation r2 = eval(e2);
810
811                        if ( ! r1.hasKnownValue ) return;
812                        if ( ! r2.hasKnownValue ) return;
813
814                        if (r1.knownValue != r2.knownValue) return;
815
816                        visit_children = false;
817                        result = true;
818                }
819
820        public:
821
822                void previsit( const ast::Node * ) { assert(false); }
823
824                void previsit( const ast::Expr * e1 ) {
825                        tryMatchOnStaticValue( e1 );
826                        visit_children = false;
827                }
828
829                void previsit( const ast::CastExpr * e1 ) {
830                        tryMatchOnStaticValue( e1 );
831
832                        if (result) {
833                                assert (visit_children == false);
834                        } else {
835                                assert (visit_children == true);
836                                visit_children = false;
837
838                                auto e2c = dynamic_cast< const ast::CastExpr * >( e2 );
839                                if ( ! e2c ) return;
840
841                                // inspect casts' target types
842                                if ( ! unifyExact(
843                                        e1->result, e2c->result, tenv, need, have, open, widen ) ) return;
844
845                                // inspect casts' inner expressions
846                                result = unify( e1->arg, e2c->arg, tenv, need, have, open, widen );
847                        }
848                }
849
850                void previsit( const ast::VariableExpr * e1 ) {
851                        tryMatchOnStaticValue( e1 );
852
853                        if (result) {
854                                assert (visit_children == false);
855                        } else {
856                                assert (visit_children == true);
857                                visit_children = false;
858
859                                auto e2v = dynamic_cast< const ast::VariableExpr * >( e2 );
860                                if ( ! e2v ) return;
861
862                                assert(e1->var);
863                                assert(e2v->var);
864
865                                // conservative: variable exprs match if their declarations are represented by the same C++ AST object
866                                result = (e1->var == e2v->var);
867                        }
868                }
869
870                void previsit( const ast::SizeofExpr * e1 ) {
871                        tryMatchOnStaticValue( e1 );
872
873                        if (result) {
874                                assert (visit_children == false);
875                        } else {
876                                assert (visit_children == true);
877                                visit_children = false;
878
879                                auto e2so = dynamic_cast< const ast::SizeofExpr * >( e2 );
880                                if ( ! e2so ) return;
881
882                                assert((e1->type != nullptr) ^ (e1->expr != nullptr));
883                                assert((e2so->type != nullptr) ^ (e2so->expr != nullptr));
884                                if ( ! (e1->type && e2so->type) )  return;
885
886                                // expression unification calls type unification (mutual recursion)
887                                result = unifyExact( e1->type, e2so->type, tenv, need, have, open, widen );
888                        }
889                }
890
891                UnifyExpr( const ast::Expr * e2, ast::TypeEnvironment & env, ast::AssertionSet & need,
892                        ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
893                : e2( e2 ), tenv(env), need(need), have(have), open(open), widen(widen), result(false) {}
894        };
895
896        static bool unify( const ast::Expr * e1, const ast::Expr * e2, ast::TypeEnvironment & env,
897                ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
898                WidenMode widen ) {
899                assert( e1 && e2 );
900                return ast::Pass<UnifyExpr>::read( e1, e2, env, need, have, open, widen );
901        }
902
903        class Unify_new final : public ast::WithShortCircuiting {
904                const ast::Type * type2;
905                ast::TypeEnvironment & tenv;
906                ast::AssertionSet & need;
907                ast::AssertionSet & have;
908                const ast::OpenVarSet & open;
909                WidenMode widen;
910        public:
911                static size_t traceId;
912                bool result;
913
914                Unify_new(
915                        const ast::Type * type2, ast::TypeEnvironment & env, ast::AssertionSet & need,
916                        ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen )
917                : type2(type2), tenv(env), need(need), have(have), open(open), widen(widen),
918                result(false) {}
919
920                void previsit( const ast::Node * ) { visit_children = false; }
921
922                void postvisit( const ast::VoidType * ) {
923                        result = dynamic_cast< const ast::VoidType * >( type2 );
924                }
925
926                void postvisit( const ast::BasicType * basic ) {
927                        if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) {
928                                result = basic->kind == basic2->kind;
929                        }
930                }
931
932                void postvisit( const ast::PointerType * pointer ) {
933                        if ( auto pointer2 = dynamic_cast< const ast::PointerType * >( type2 ) ) {
934                                result = unifyExact(
935                                        pointer->base, pointer2->base, tenv, need, have, open,
936                                        noWiden());
937                        }
938                }
939
940                void postvisit( const ast::ArrayType * array ) {
941                        auto array2 = dynamic_cast< const ast::ArrayType * >( type2 );
942                        if ( ! array2 ) return;
943
944                        if ( array->isVarLen != array2->isVarLen ) return;
945                        if ( (array->dimension != nullptr) != (array2->dimension != nullptr) ) return;
946
947                        if ( array->dimension ) {
948                                assert( array2->dimension );
949                                // type unification calls expression unification (mutual recursion)
950                                if ( ! unify(array->dimension, array2->dimension,
951                                    tenv, need, have, open, widen) ) return;
952                        }
953
954                        result = unifyExact(
955                                array->base, array2->base, tenv, need, have, open, noWiden());
956                }
957
958                void postvisit( const ast::ReferenceType * ref ) {
959                        if ( auto ref2 = dynamic_cast< const ast::ReferenceType * >( type2 ) ) {
960                                result = unifyExact(
961                                        ref->base, ref2->base, tenv, need, have, open, noWiden());
962                        }
963                }
964
965        private:
966
967                template< typename Iter >
968                static bool unifyTypeList(
969                        Iter crnt1, Iter end1, Iter crnt2, Iter end2, ast::TypeEnvironment & env,
970                        ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open
971                ) {
972                        while ( crnt1 != end1 && crnt2 != end2 ) {
973                                const ast::Type * t1 = *crnt1;
974                                const ast::Type * t2 = *crnt2;
975                                bool isTuple1 = Tuples::isTtype( t1 );
976                                bool isTuple2 = Tuples::isTtype( t2 );
977
978                                // assumes here that ttype *must* be last parameter
979                                if ( isTuple1 && ! isTuple2 ) {
980                                        // combine remainder of list2, then unify
981                                        return unifyExact(
982                                                t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
983                                                noWiden() );
984                                } else if ( ! isTuple1 && isTuple2 ) {
985                                        // combine remainder of list1, then unify
986                                        return unifyExact(
987                                                tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
988                                                noWiden() );
989                                }
990
991                                if ( ! unifyExact(
992                                        t1, t2, env, need, have, open, noWiden() )
993                                ) return false;
994
995                                ++crnt1; ++crnt2;
996                        }
997
998                        // May get to the end of one argument list before the other. This is only okay if the
999                        // other is a ttype
1000                        if ( crnt1 != end1 ) {
1001                                // try unifying empty tuple with ttype
1002                                const ast::Type * t1 = *crnt1;
1003                                if ( ! Tuples::isTtype( t1 ) ) return false;
1004                                return unifyExact(
1005                                        t1, tupleFromTypes( crnt2, end2 ), env, need, have, open,
1006                                        noWiden() );
1007                        } else if ( crnt2 != end2 ) {
1008                                // try unifying empty tuple with ttype
1009                                const ast::Type * t2 = *crnt2;
1010                                if ( ! Tuples::isTtype( t2 ) ) return false;
1011                                return unifyExact(
1012                                        tupleFromTypes( crnt1, end1 ), t2, env, need, have, open,
1013                                        noWiden() );
1014                        }
1015
1016                        return true;
1017                }
1018
1019                static bool unifyTypeList(
1020                        const std::vector< ast::ptr< ast::Type > > & list1,
1021                        const std::vector< ast::ptr< ast::Type > > & list2,
1022                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
1023                        const ast::OpenVarSet & open
1024                ) {
1025                        return unifyTypeList(
1026                                list1.begin(), list1.end(), list2.begin(), list2.end(), env, need, have, open);
1027                }
1028
1029                static void markAssertionSet( ast::AssertionSet & assns, const ast::VariableExpr * assn ) {
1030                        auto i = assns.find( assn );
1031                        if ( i != assns.end() ) {
1032                                i->second.isUsed = true;
1033                        }
1034                }
1035
1036                /// mark all assertions in `type` used in both `assn1` and `assn2`
1037                static void markAssertions(
1038                        ast::AssertionSet & assn1, ast::AssertionSet & assn2,
1039                        const ast::FunctionType * type
1040                ) {
1041                        for ( auto & assert : type->assertions ) {
1042                                markAssertionSet( assn1, assert );
1043                                markAssertionSet( assn2, assert );
1044                        }
1045                }
1046
1047        public:
1048                void postvisit( const ast::FunctionType * func ) {
1049                        auto func2 = dynamic_cast< const ast::FunctionType * >( type2 );
1050                        if ( ! func2 ) return;
1051
1052                        if ( func->isVarArgs != func2->isVarArgs ) return;
1053
1054                        // Flatten the parameter lists for both functions so that tuple structure does not
1055                        // affect unification. Does not actually mutate function parameters.
1056                        auto params = flattenList( func->params, tenv );
1057                        auto params2 = flattenList( func2->params, tenv );
1058
1059                        // sizes don't have to match if ttypes are involved; need to be more precise w.r.t.
1060                        // where the ttype is to prevent errors
1061                        if (
1062                                ( params.size() != params2.size() || func->returns.size() != func2->returns.size() )
1063                                && ! func->isTtype()
1064                                && ! func2->isTtype()
1065                        ) return;
1066
1067                        if ( ! unifyTypeList( params, params2, tenv, need, have, open ) ) return;
1068                        if ( ! unifyTypeList(
1069                                func->returns, func2->returns, tenv, need, have, open ) ) return;
1070
1071                        markAssertions( have, need, func );
1072                        markAssertions( have, need, func2 );
1073
1074                        result = true;
1075                }
1076
1077        private:
1078                // Returns: other, cast as XInstType
1079                // Assigns this->result: whether types are compatible (up to generic parameters)
1080                template< typename XInstType >
1081                const XInstType * handleRefType( const XInstType * inst, const ast::Type * other ) {
1082                        // check that the other type is compatible and named the same
1083                        auto otherInst = dynamic_cast< const XInstType * >( other );
1084                        if (otherInst && inst->name == otherInst->name) 
1085                                this->result = otherInst;
1086                        return otherInst;
1087                }
1088
1089                /// Creates a tuple type based on a list of TypeExpr
1090                template< typename Iter >
1091                static const ast::Type * tupleFromExprs(
1092                        const ast::TypeExpr * param, Iter & crnt, Iter end, ast::CV::Qualifiers qs
1093                ) {
1094                        std::vector< ast::ptr< ast::Type > > types;
1095                        do {
1096                                types.emplace_back( param->type );
1097
1098                                ++crnt;
1099                                if ( crnt == end ) break;
1100                                param = strict_dynamic_cast< const ast::TypeExpr * >( crnt->get() );
1101                        } while(true);
1102
1103                        return new ast::TupleType{ std::move(types), qs };
1104                }
1105
1106                template< typename XInstType >
1107                void handleGenericRefType( const XInstType * inst, const ast::Type * other ) {
1108                        // check that other type is compatible and named the same
1109                        const XInstType * otherInst = handleRefType( inst, other );
1110                        if ( ! this->result ) return;
1111
1112                        // check that parameters of types unify, if any
1113                        const std::vector< ast::ptr< ast::Expr > > & params = inst->params;
1114                        const std::vector< ast::ptr< ast::Expr > > & params2 = otherInst->params;
1115
1116                        auto it = params.begin();
1117                        auto jt = params2.begin();
1118                        for ( ; it != params.end() && jt != params2.end(); ++it, ++jt ) {
1119                                auto param = strict_dynamic_cast< const ast::TypeExpr * >( it->get() );
1120                                auto param2 = strict_dynamic_cast< const ast::TypeExpr * >( jt->get() );
1121
1122                                ast::ptr< ast::Type > pty = param->type;
1123                                ast::ptr< ast::Type > pty2 = param2->type;
1124
1125                                bool isTuple = Tuples::isTtype( pty );
1126                                bool isTuple2 = Tuples::isTtype( pty2 );
1127
1128                                if ( isTuple && isTuple2 ) {
1129                                        ++it; ++jt;  // skip ttype parameters before break
1130                                } else if ( isTuple ) {
1131                                        // bundle remaining params into tuple
1132                                        pty2 = tupleFromExprs( param2, jt, params2.end(), pty->qualifiers );
1133                                        ++it;  // skip ttype parameter for break
1134                                } else if ( isTuple2 ) {
1135                                        // bundle remaining params into tuple
1136                                        pty = tupleFromExprs( param, it, params.end(), pty2->qualifiers );
1137                                        ++jt;  // skip ttype parameter for break
1138                                }
1139
1140                                if ( ! unifyExact(
1141                                                pty, pty2, tenv, need, have, open, noWiden() ) ) {
1142                                        result = false;
1143                                        return;
1144                                }
1145
1146                                // ttype parameter should be last
1147                                if ( isTuple || isTuple2 ) break;
1148                        }
1149                        result = it == params.end() && jt == params2.end();
1150                }
1151
1152        public:
1153                void postvisit( const ast::StructInstType * aggrType ) {
1154                        handleGenericRefType( aggrType, type2 );
1155                }
1156
1157                void postvisit( const ast::UnionInstType * aggrType ) {
1158                        handleGenericRefType( aggrType, type2 );
1159                }
1160
1161                void postvisit( const ast::EnumInstType * aggrType ) {
1162                        handleRefType( aggrType, type2 );
1163                }
1164
1165                void postvisit( const ast::TraitInstType * aggrType ) {
1166                        handleRefType( aggrType, type2 );
1167                }
1168
1169                void postvisit( const ast::TypeInstType * typeInst ) {
1170                        // assert( open.find( *typeInst ) == open.end() );
1171                        auto otherInst = dynamic_cast< const ast::TypeInstType * >( type2 );
1172                        if (otherInst && typeInst->name == otherInst->name) 
1173                                this->result = otherInst;
1174                        // return otherInst;
1175                }
1176
1177        private:
1178                /// Creates a tuple type based on a list of Type
1179
1180                static bool unifyList(
1181                        const std::vector< ast::ptr< ast::Type > > & list1,
1182                        const std::vector< ast::ptr< ast::Type > > & list2, ast::TypeEnvironment & env,
1183                        ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open
1184                ) {
1185                        auto crnt1 = list1.begin();
1186                        auto crnt2 = list2.begin();
1187                        while ( crnt1 != list1.end() && crnt2 != list2.end() ) {
1188                                const ast::Type * t1 = *crnt1;
1189                                const ast::Type * t2 = *crnt2;
1190                                bool isTuple1 = Tuples::isTtype( t1 );
1191                                bool isTuple2 = Tuples::isTtype( t2 );
1192
1193                                // assumes ttype must be last parameter
1194                                if ( isTuple1 && ! isTuple2 ) {
1195                                        // combine entirety of list2, then unify
1196                                        return unifyExact(
1197                                                t1, tupleFromTypes( list2 ), env, need, have, open,
1198                                                noWiden() );
1199                                } else if ( ! isTuple1 && isTuple2 ) {
1200                                        // combine entirety of list1, then unify
1201                                        return unifyExact(
1202                                                tupleFromTypes( list1 ), t2, env, need, have, open,
1203                                                noWiden() );
1204                                }
1205
1206                                if ( ! unifyExact(
1207                                        t1, t2, env, need, have, open, noWiden() )
1208                                ) return false;
1209
1210                                ++crnt1; ++crnt2;
1211                        }
1212
1213                        if ( crnt1 != list1.end() ) {
1214                                // try unifying empty tuple type with ttype
1215                                const ast::Type * t1 = *crnt1;
1216                                if ( ! Tuples::isTtype( t1 ) ) return false;
1217                                // xxx - this doesn't generate an empty tuple, contrary to comment; both ported
1218                                // from Rob's code
1219                                return unifyExact(
1220                                                t1, tupleFromTypes( list2 ), env, need, have, open,
1221                                                noWiden() );
1222                        } else if ( crnt2 != list2.end() ) {
1223                                // try unifying empty tuple with ttype
1224                                const ast::Type * t2 = *crnt2;
1225                                if ( ! Tuples::isTtype( t2 ) ) return false;
1226                                // xxx - this doesn't generate an empty tuple, contrary to comment; both ported
1227                                // from Rob's code
1228                                return unifyExact(
1229                                                tupleFromTypes( list1 ), t2, env, need, have, open,
1230                                                noWiden() );
1231                        }
1232
1233                        return true;
1234                }
1235
1236        public:
1237                void postvisit( const ast::TupleType * tuple ) {
1238                        auto tuple2 = dynamic_cast< const ast::TupleType * >( type2 );
1239                        if ( ! tuple2 ) return;
1240
1241                        ast::Pass<TtypeExpander_new> expander{ tenv };
1242
1243                        const ast::Type * flat = tuple->accept( expander );
1244                        const ast::Type * flat2 = tuple2->accept( expander );
1245
1246                        auto types = flatten( flat );
1247                        auto types2 = flatten( flat2 );
1248
1249                        result = unifyList( types, types2, tenv, need, have, open );
1250                }
1251
1252                void postvisit( const ast::VarArgsType * ) {
1253                        result = dynamic_cast< const ast::VarArgsType * >( type2 );
1254                }
1255
1256                void postvisit( const ast::ZeroType * ) {
1257                        result = dynamic_cast< const ast::ZeroType * >( type2 );
1258                }
1259
1260                void postvisit( const ast::OneType * ) {
1261                        result = dynamic_cast< const ast::OneType * >( type2 );
1262                }
1263
1264          private:
1265                template< typename RefType > void handleRefType( RefType *inst, Type *other );
1266                template< typename RefType > void handleGenericRefType( RefType *inst, Type *other );
1267        };
1268
1269        // size_t Unify_new::traceId = Stats::Heap::new_stacktrace_id("Unify_new");
1270        bool unify(
1271                        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
1272                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
1273                        ast::OpenVarSet & open
1274        ) {
1275                ast::ptr<ast::Type> common;
1276                return unify( type1, type2, env, need, have, open, common );
1277        }
1278
1279        bool unify(
1280                        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
1281                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
1282                        ast::OpenVarSet & open, ast::ptr<ast::Type> & common
1283        ) {
1284                ast::OpenVarSet closed;
1285                // findOpenVars( type1, open, closed, need, have, FirstClosed );
1286                findOpenVars( type2, open, closed, need, have, env, FirstOpen );
1287                return unifyInexact(
1288                        type1, type2, env, need, have, open, WidenMode{ true, true }, common );
1289        }
1290
1291        bool unifyExact(
1292                        const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
1293                        ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
1294                        WidenMode widen
1295        ) {
1296                if ( type1->qualifiers != type2->qualifiers ) return false;
1297
1298                auto var1 = dynamic_cast< const ast::TypeInstType * >( type1 );
1299                auto var2 = dynamic_cast< const ast::TypeInstType * >( type2 );
1300                ast::OpenVarSet::const_iterator
1301                        entry1 = var1 ? open.find( *var1 ) : open.end(),
1302                        entry2 = var2 ? open.find( *var2 ) : open.end();
1303                // bool isopen1 = entry1 != open.end();
1304                // bool isopen2 = entry2 != open.end();
1305                bool isopen1 = var1 && env.lookup(*var1);
1306                bool isopen2 = var2 && env.lookup(*var2);
1307
1308                /*
1309                if ( isopen1 && isopen2 ) {
1310                        if ( entry1->second.kind != entry2->second.kind ) return false;
1311                        return env.bindVarToVar(
1312                                var1, var2, ast::TypeData{ entry1->second, entry2->second }, need, have,
1313                                open, widen );
1314                } else if ( isopen1 ) {
1315                        return env.bindVar( var1, type2, entry1->second, need, have, open, widen );
1316                } else if ( isopen2 ) {
1317                        return env.bindVar( var2, type1, entry2->second, need, have, open, widen, symtab );
1318                } */
1319                if ( isopen1 && isopen2 ) {
1320                        if ( var1->base->kind != var2->base->kind ) return false;
1321                        return env.bindVarToVar(
1322                                var1, var2, ast::TypeData{ var1->base->kind, var1->base->sized||var2->base->sized }, need, have,
1323                                open, widen );
1324                } else if ( isopen1 ) {
1325                        return env.bindVar( var1, type2, ast::TypeData{var1->base}, need, have, open, widen );
1326                } else if ( isopen2 ) {
1327                        return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen );
1328                }else {
1329                        return ast::Pass<Unify_new>::read(
1330                                type1, type2, env, need, have, open, widen );
1331                }
1332               
1333        }
1334
1335        bool unifyInexact(
1336                        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
1337                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
1338                        const ast::OpenVarSet & open, WidenMode widen,
1339                        ast::ptr<ast::Type> & common
1340        ) {
1341                ast::CV::Qualifiers q1 = type1->qualifiers, q2 = type2->qualifiers;
1342
1343                // force t1 and t2 to be cloned if their qualifiers must be stripped, so that type1 and
1344                // type2 are left unchanged; calling convention forces type{1,2}->strong_ref >= 1
1345                ast::Type * t1 = shallowCopy(type1.get());
1346                ast::Type * t2 = shallowCopy(type2.get());
1347                t1->qualifiers = {};
1348                t2->qualifiers = {};
1349                ast::ptr< ast::Type > t1_(t1);
1350                ast::ptr< ast::Type > t2_(t2);
1351
1352                if ( unifyExact( t1, t2, env, need, have, open, widen ) ) {
1353                        // if exact unification on unqualified types, try to merge qualifiers
1354                        if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) {
1355                                t1->qualifiers = q1 | q2;
1356                                common = t1;
1357                                return true;
1358                        } else {
1359                                return false;
1360                        }
1361
1362                } else if (( common = commonType( t1, t2, env, need, have, open, widen ))) {
1363                        // no exact unification, but common type
1364                        auto c = shallowCopy(common.get());
1365                        c->qualifiers = q1 | q2;
1366                        common = c;
1367                        return true;
1368                } else {
1369                        return false;
1370                }
1371        }
1372
1373        ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ) {
1374                if ( func->returns.empty() ) return new ast::VoidType{};
1375                if ( func->returns.size() == 1 ) return func->returns[0];
1376
1377                std::vector<ast::ptr<ast::Type>> tys;
1378                for ( const auto & decl : func->returns ) {
1379                        tys.emplace_back( decl );
1380                }
1381                return new ast::TupleType{ std::move(tys) };
1382        }
1383} // namespace ResolvExpr
1384
1385// Local Variables: //
1386// tab-width: 4 //
1387// mode: c++ //
1388// compile-command: "make install" //
1389// End: //
Note: See TracBrowser for help on using the repository browser.