Changeset b067d9b for src/ResolvExpr


Ignore:
Timestamp:
Oct 29, 2019, 4:01:24 PM (6 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum, stuck-waitfor-destruct
Children:
773db65, 9421f3d8
Parents:
7951100 (diff), 8364209 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

Location:
src/ResolvExpr
Files:
13 added
32 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/AdjustExprType.cc

    r7951100 rb067d9b  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // AdjustExprType.cc --
     7// AdjustExprType_old.cc --
    88//
    99// Author           : Richard C. Bilson
     
    1414//
    1515
     16#include "AST/Node.hpp"
     17#include "AST/Pass.hpp"
     18#include "AST/SymbolTable.hpp"
     19#include "AST/Type.hpp"
     20#include "AST/TypeEnvironment.hpp"
    1621#include "Common/PassVisitor.h"
    1722#include "SymTab/Indexer.h"       // for Indexer
     
    2227
    2328namespace ResolvExpr {
    24         class AdjustExprType : public WithShortCircuiting {
    25           public:
    26                 AdjustExprType( const TypeEnvironment & env, const SymTab::Indexer & indexer );
     29
     30namespace {
     31        class AdjustExprType_old final : public WithShortCircuiting {
     32                public:
     33                AdjustExprType_old( const TypeEnvironment & env, const SymTab::Indexer & indexer );
    2734                void premutate( VoidType * ) { visit_children = false; }
    2835                void premutate( BasicType * ) { visit_children = false; }
     
    4047                void premutate( OneType * ) { visit_children = false; }
    4148
    42                 Type * postmutate( ArrayType *arrayType );
    43                 Type * postmutate( FunctionType *functionType );
    44                 Type * postmutate( TypeInstType *aggregateUseType );
     49                Type * postmutate( ArrayType * arrayType );
     50                Type * postmutate( FunctionType * functionType );
     51                Type * postmutate( TypeInstType * aggregateUseType );
    4552
    46           private:
     53                private:
    4754                const TypeEnvironment & env;
    4855                const SymTab::Indexer & indexer;
    4956        };
    5057
    51         void adjustExprType( Type *&type, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
    52                 PassVisitor<AdjustExprType> adjuster( env, indexer );
    53                 Type *newType = type->acceptMutator( adjuster );
    54                 type = newType;
    55         }
    56 
    57         void adjustExprType( Type *& type ) {
    58                 TypeEnvironment env;
    59                 SymTab::Indexer indexer;
    60                 adjustExprType( type, env, indexer );
    61         }
    62 
    63         AdjustExprType::AdjustExprType( const TypeEnvironment &env, const SymTab::Indexer &indexer )
     58        AdjustExprType_old::AdjustExprType_old( const TypeEnvironment &env, const SymTab::Indexer &indexer )
    6459                : env( env ), indexer( indexer ) {
    6560        }
    6661
    67         Type * AdjustExprType::postmutate( ArrayType * arrayType ) {
    68                 PointerType *pointerType = new PointerType{ arrayType->get_qualifiers(), arrayType->base };
     62        Type * AdjustExprType_old::postmutate( ArrayType * arrayType ) {
     63                PointerType * pointerType = new PointerType{ arrayType->get_qualifiers(), arrayType->base };
    6964                arrayType->base = nullptr;
    7065                delete arrayType;
     
    7267        }
    7368
    74         Type * AdjustExprType::postmutate( FunctionType * functionType ) {
     69        Type * AdjustExprType_old::postmutate( FunctionType * functionType ) {
    7570                return new PointerType{ Type::Qualifiers(), functionType };
    7671        }
    7772
    78         Type * AdjustExprType::postmutate( TypeInstType * typeInst ) {
    79                 if ( const EqvClass* eqvClass = env.lookup( typeInst->get_name() ) ) {
     73        Type * AdjustExprType_old::postmutate( TypeInstType * typeInst ) {
     74                if ( const EqvClass * eqvClass = env.lookup( typeInst->get_name() ) ) {
    8075                        if ( eqvClass->data.kind == TypeDecl::Ftype ) {
    8176                                return new PointerType{ Type::Qualifiers(), typeInst };
    8277                        }
    83                 } else if ( NamedTypeDecl *ntDecl = indexer.lookupType( typeInst->get_name() ) ) {
    84                         if ( TypeDecl *tyDecl = dynamic_cast< TypeDecl* >( ntDecl ) ) {
     78                } else if ( const NamedTypeDecl * ntDecl = indexer.lookupType( typeInst->get_name() ) ) {
     79                        if ( const TypeDecl * tyDecl = dynamic_cast< const TypeDecl * >( ntDecl ) ) {
    8580                                if ( tyDecl->get_kind() == TypeDecl::Ftype ) {
    8681                                        return new PointerType{ Type::Qualifiers(), typeInst };
     
    9085                return typeInst;
    9186        }
     87} // anonymous namespace
     88
     89void adjustExprType( Type *&type, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
     90        PassVisitor<AdjustExprType_old> adjuster( env, indexer );
     91        Type * newType = type->acceptMutator( adjuster );
     92        type = newType;
     93}
     94
     95void adjustExprType( Type *& type ) {
     96        TypeEnvironment env;
     97        SymTab::Indexer indexer;
     98        adjustExprType( type, env, indexer );
     99}
     100
     101namespace {
     102        struct AdjustExprType_new final : public ast::WithShortCircuiting {
     103                const ast::TypeEnvironment & tenv;
     104                const ast::SymbolTable & symtab;
     105
     106                AdjustExprType_new( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
     107                : tenv( e ), symtab( syms ) {}
     108
     109                void premutate( const ast::VoidType * ) { visit_children = false; }
     110                void premutate( const ast::BasicType * ) { visit_children = false; }
     111                void premutate( const ast::PointerType * ) { visit_children = false; }
     112                void premutate( const ast::ArrayType * ) { visit_children = false; }
     113                void premutate( const ast::FunctionType * ) { visit_children = false; }
     114                void premutate( const ast::StructInstType * ) { visit_children = false; }
     115                void premutate( const ast::UnionInstType * ) { visit_children = false; }
     116                void premutate( const ast::EnumInstType * ) { visit_children = false; }
     117                void premutate( const ast::TraitInstType * ) { visit_children = false; }
     118                void premutate( const ast::TypeInstType * ) { visit_children = false; }
     119                void premutate( const ast::TupleType * ) { visit_children = false; }
     120                void premutate( const ast::VarArgsType * ) { visit_children = false; }
     121                void premutate( const ast::ZeroType * ) { visit_children = false; }
     122                void premutate( const ast::OneType * ) { visit_children = false; }
     123
     124                const ast::Type * postmutate( const ast::ArrayType * at ) {
     125                        return new ast::PointerType{ at->base, at->qualifiers };
     126                }
     127
     128                const ast::Type * postmutate( const ast::FunctionType * ft ) {
     129                        return new ast::PointerType{ ft };
     130                }
     131
     132                const ast::Type * postmutate( const ast::TypeInstType * inst ) {
     133                        // replace known function-type-variables with pointer-to-function
     134                        if ( const ast::EqvClass * eqvClass = tenv.lookup( inst->name ) ) {
     135                                if ( eqvClass->data.kind == ast::TypeVar::Ftype ) {
     136                                        return new ast::PointerType{ inst };
     137                                }
     138                        } else if ( const ast::NamedTypeDecl * ntDecl = symtab.lookupType( inst->name ) ) {
     139                                if ( auto tyDecl = dynamic_cast< const ast::TypeDecl * >( ntDecl ) ) {
     140                                        if ( tyDecl->kind == ast::TypeVar::Ftype ) {
     141                                                return new ast::PointerType{ inst };
     142                                        }
     143                                }
     144                        }
     145                        return inst;
     146                }
     147        };
     148} // anonymous namespace
     149
     150const ast::Type * adjustExprType(
     151        const ast::Type * type, const ast::TypeEnvironment & env, const ast::SymbolTable & symtab
     152) {
     153        ast::Pass<AdjustExprType_new> adjuster{ env, symtab };
     154        return type->accept( adjuster );
     155}
     156
    92157} // namespace ResolvExpr
    93158
  • src/ResolvExpr/Alternative.cc

    r7951100 rb067d9b  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sat May 16 23:44:23 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat May 16 23:54:23 2015
    13 // Update Count     : 2
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Thu Oct 11 10:55:00 2018
     13// Update Count     : 3
    1414//
    1515
     
    2020#include <utility>                       // for move
    2121
    22 #include "Common/utility.h"              // for maybeClone
     22#include "Common/utility.h"              // for cloneAll
    2323#include "ResolvExpr/Cost.h"             // for Cost, Cost::zero, operator<<
    2424#include "ResolvExpr/TypeEnvironment.h"  // for TypeEnvironment
     
    2727
    2828namespace ResolvExpr {
    29         Alternative::Alternative() : cost( Cost::zero ), cvtCost( Cost::zero ), expr( nullptr ) {}
     29        Alternative::Alternative()
     30        : cost( Cost::zero ), cvtCost( Cost::zero ), expr( nullptr ), env(), openVars(), need() {}
    3031
    31         Alternative::Alternative( Expression *expr, const TypeEnvironment &env, const Cost& cost )
    32                 : cost( cost ), cvtCost( Cost::zero ), expr( expr ), env( env ) {}
     32        Alternative::Alternative( Expression *expr, const TypeEnvironment &env )
     33        : cost( Cost::zero ), cvtCost( Cost::zero ), expr( expr ), env( env ), openVars(), need() {}
     34       
     35        Alternative::Alternative( const Alternative &o, Expression *expr, const Cost &cost )
     36        : cost( cost ), cvtCost( Cost::zero ), expr( expr ), env( o.env ), openVars( o.openVars ),
     37          need() { cloneAll( o.need, need ); }
    3338
    34         Alternative::Alternative( Expression *expr, const TypeEnvironment &env, const Cost& cost, const Cost &cvtCost )
    35                 : cost( cost ), cvtCost( cvtCost ), expr( expr ), env( env ) {}
     39        Alternative::Alternative( Expression *expr, const TypeEnvironment &env,
     40                const OpenVarSet& openVars, const AssertionList& oneed, const Cost& cost )
     41        : cost( cost ), cvtCost( Cost::zero ), expr( expr ), env( env ), openVars( openVars ),
     42          need() { cloneAll( oneed, need ); }
    3643
    37         Alternative::Alternative( const Alternative &other ) : cost( other.cost ), cvtCost( other.cvtCost ), expr( maybeClone( other.expr ) ), env( other.env ) {
    38         }
     44        Alternative::Alternative( Expression *expr, const TypeEnvironment &env,
     45                const OpenVarSet& openVars, const AssertionList& oneed, const Cost& cost,
     46                const Cost &cvtCost )
     47        : cost( cost ), cvtCost( cvtCost ), expr( expr ), env( env ), openVars( openVars ),
     48          need() { cloneAll( oneed, need ); }
     49       
     50        Alternative::Alternative( Expression *expr, const TypeEnvironment &env,
     51                const OpenVarSet &openVars, const AssertionSet &oneed, const Cost &cost)
     52        : cost( cost ), cvtCost( Cost::zero ), expr( expr ), env( env ), openVars( openVars ),
     53          need() { cloneAll( oneed, need ); }
     54       
     55        Alternative::Alternative( Expression *expr, const TypeEnvironment &env,
     56                const OpenVarSet &openVars, const AssertionSet &oneed, const Cost &cost,
     57                const Cost& cvtCost )
     58        : cost( cost ), cvtCost( cvtCost ), expr( expr ), env( env ), openVars( openVars ),
     59          need() { cloneAll( oneed, need ); }
     60       
     61        Alternative::Alternative( Expression *expr, TypeEnvironment &&env, OpenVarSet &&openVars,
     62                AssertionSet &&needSet, const Cost &cost )
     63        : cost( cost ), cvtCost( Cost::zero ), expr( expr ), env( std::move(env) ),
     64          openVars( std::move(openVars) ), need( needSet.begin(), needSet.end() ) {}
     65       
     66        Alternative::Alternative( Expression *expr, TypeEnvironment &&env, OpenVarSet &&openVars,
     67                AssertionSet &&needSet, const Cost &cost, const Cost &cvtCost )
     68        : cost( cost ), cvtCost( cvtCost ), expr( expr ), env( std::move(env) ),
     69          openVars( std::move(openVars) ), need( needSet.begin(), needSet.end() ) {}
     70
     71        Alternative::Alternative( const Alternative &other )
     72        : cost( other.cost ), cvtCost( other.cvtCost ), expr( maybeClone( other.expr ) ),
     73          env( other.env ), openVars( other.openVars ), need() { cloneAll( other.need, need ); }
    3974
    4075        Alternative &Alternative::operator=( const Alternative &other ) {
     
    4580                expr = maybeClone( other.expr );
    4681                env = other.env;
     82                openVars = other.openVars;
     83                need.clear();
     84                cloneAll( other.need, need );
    4785                return *this;
    4886        }
    4987
    50         Alternative::Alternative( Alternative && other ) : cost( other.cost ), cvtCost( other.cvtCost ), expr( other.expr ), env( std::move( other.env ) ) {
    51                 other.expr = nullptr;
    52         }
     88        Alternative::Alternative( Alternative && other )
     89        : cost( other.cost ), cvtCost( other.cvtCost ), expr( other.expr ),
     90          env( std::move( other.env ) ), openVars( std::move( other.openVars ) ),
     91          need( std::move( other.need ) ) { other.expr = nullptr; }
    5392
    5493        Alternative & Alternative::operator=( Alternative && other ) {
     
    5998                expr = other.expr;
    6099                env = std::move( other.env );
     100                openVars = std::move( other.openVars );
     101                need = std::move( other.need );
    61102                other.expr = nullptr;
    62103                return *this;
     
    64105
    65106        Alternative::~Alternative() {
     107                for ( AssertionItem& n : need ) { delete n.decl; }
    66108                delete expr;
    67109        }
     
    78120                        os << "Null expression!" << std::endl;
    79121                } // if
    80                 os << indent << "Environment: ";
     122                os << indent << "Environment:";
    81123                env.print( os, indent+1 );
    82124                os << std::endl;
    83         }
    84 
    85         void splice( AltList& dst, AltList& src ) {
    86                 dst.reserve( dst.size() + src.size() );
    87                 for ( Alternative& alt : src ) {
    88                         dst.push_back( std::move(alt) );
    89                 }
    90                 src.clear();
    91         }
    92 
    93         void spliceBegin( AltList& dst, AltList& src ) {
    94                 splice( src, dst );
    95                 dst.swap( src );
    96125        }
    97126
  • src/ResolvExpr/Alternative.h

    r7951100 rb067d9b  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sat May 16 23:45:43 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:36:36 2017
    13 // Update Count     : 3
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Thu Oct 11 10:55:00 2018
     13// Update Count     : 4
    1414//
    1515
     
    2020
    2121#include "Cost.h"             // for Cost
    22 #include "TypeEnvironment.h"  // for TypeEnvironment
     22#include "TypeEnvironment.h"  // for TypeEnvironment, AssertionSetValue
     23
     24#include "Common/utility.h"   // for maybeClone
    2325
    2426class Expression;
    2527
    2628namespace ResolvExpr {
     29        /// One assertion to resolve
     30        struct AssertionItem {
     31                const DeclarationWithType* decl;
     32                AssertionSetValue info;
     33
     34                AssertionItem() = default;
     35                AssertionItem( const DeclarationWithType* decl, const AssertionSetValue& info )
     36                : decl(decl), info(info) {}
     37                AssertionItem( const AssertionSet::value_type& e ) : decl(e.first), info(e.second) {}
     38                operator AssertionSet::value_type () const { return { decl, info }; }
     39
     40                // to support cloneAll
     41                AssertionItem clone() const { return { maybeClone(decl), info }; }
     42        };
     43        /// A list of unresolved assertions
     44        using AssertionList = std::vector<AssertionItem>;
     45
     46        /// Clones an assertion list into an assertion set
     47        static inline void cloneAll( const AssertionList& src, AssertionSet& dst ) {
     48                for ( const AssertionItem& item : src ) {
     49                        dst.emplace( maybeClone(item.decl), item.info );
     50                }
     51        }
     52
     53        /// Clones an assertion set into an assertion list
     54        static inline void cloneAll( const AssertionSet& src, AssertionList& dst ) {
     55                dst.reserve( dst.size() + src.size() );
     56                for ( const auto& entry : src ) {
     57                        dst.emplace_back( maybeClone(entry.first), entry.second );
     58                }
     59        }
     60
     61        /// Clones an assertion list into an assertion list
     62        static inline void cloneAll( const AssertionList& src, AssertionList& dst ) {
     63                dst.reserve( dst.size() + src.size() );
     64                for ( const AssertionItem& item : src ) {
     65                        dst.emplace_back( maybeClone(item.decl), item.info );
     66                }
     67        }
     68
     69        /// One option for resolution of an expression
    2770        struct Alternative {
    2871                Alternative();
    29                 Alternative( Expression *expr, const TypeEnvironment &env, const Cost &cost );
    30                 Alternative( Expression *expr, const TypeEnvironment &env, const Cost &cost, const Cost &cvtCost );
     72                Alternative( Expression *expr, const TypeEnvironment &env );
     73                Alternative( const Alternative &o, Expression *expr, const Cost &cost );
     74                Alternative( Expression *expr, const TypeEnvironment &env, const OpenVarSet& openVars,
     75                        const AssertionList& need, const Cost &cost );
     76                Alternative( Expression *expr, const TypeEnvironment &env, const OpenVarSet& openVars,
     77                        const AssertionList& need, const Cost &cost, const Cost &cvtCost );
     78                Alternative( Expression *expr, const TypeEnvironment &env, const OpenVarSet &openVars,
     79                        const AssertionSet &need, const Cost &cost);
     80                Alternative( Expression *expr, const TypeEnvironment &env, const OpenVarSet &openVars,
     81                        const AssertionSet &need, const Cost &cost, const Cost& cvtCost );
     82                Alternative( Expression *expr, TypeEnvironment &&env, OpenVarSet &&openVars,
     83                        AssertionSet &&need, const Cost &cost );
     84                Alternative( Expression *expr, TypeEnvironment &&env, OpenVarSet &&openVars,
     85                        AssertionSet &&need, const Cost &cost, const Cost &cvtCost );
    3186                Alternative( const Alternative &other );
    3287                Alternative &operator=( const Alternative &other );
     
    4499                }
    45100
    46                 Cost cost;
    47                 Cost cvtCost;
    48                 Expression *expr;
    49                 TypeEnvironment env;
     101                /// Sorts by cost
     102                bool operator< ( const Alternative& o ) const { return cost < o.cost; }
     103
     104                Cost cost;            ///< Cost of the whole expression
     105                Cost cvtCost;         ///< Cost of conversions to the satisfying expression
     106                Expression *expr;     ///< Satisfying expression
     107                TypeEnvironment env;  ///< Containing type environment
     108                OpenVarSet openVars;  ///< Open variables for environment
     109                AssertionList need;   ///< Assertions which need to be resolved
    50110        };
    51111
    52112        typedef std::vector< Alternative > AltList;
    53 
    54         /// Moves all elements from src to the end of dst
    55         void splice( AltList& dst, AltList& src );
    56 
    57         /// Moves all elements from src to the beginning of dst
    58         void spliceBegin( AltList& dst, AltList& src );
    59113
    60114        static inline std::ostream & operator<<(std::ostream & os, const ResolvExpr::Alternative & alt) {
  • src/ResolvExpr/AlternativeFinder.cc

    r7951100 rb067d9b  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sat May 16 23:52:08 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb 17 11:19:39 2018
    13 // Update Count     : 33
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu Aug  8 16:35:00 2019
     13// Update Count     : 38
    1414//
    1515
     
    2525#include <vector>                  // for vector
    2626
     27#include "CompilationState.h"      // for resolvep
    2728#include "Alternative.h"           // for AltList, Alternative
    2829#include "AlternativeFinder.h"
     30#include "AST/Expr.hpp"
     31#include "AST/SymbolTable.hpp"
     32#include "AST/Type.hpp"
    2933#include "Common/SemanticError.h"  // for SemanticError
    3034#include "Common/utility.h"        // for deleteAll, printAll, CodeLocation
     
    3337#include "InitTweak/InitTweak.h"   // for getFunctionName
    3438#include "RenameVars.h"            // for RenameVars, global_renamer
     39#include "ResolveAssertions.h"     // for resolveAssertions
    3540#include "ResolveTypeof.h"         // for resolveTypeof
    3641#include "Resolver.h"              // for resolveStmtExpr
     
    4954#include "typeops.h"               // for adjustExprType, polyCost, castCost
    5055
    51 extern bool resolvep;
    5256#define PRINT( text ) if ( resolvep ) { text }
    5357//#define DEBUG_COST
    54 
    55 using std::move;
    56 
    57 /// copies any copyable type
    58 template<typename T>
    59 T copy(const T& x) { return x; }
    6058
    6159namespace ResolvExpr {
     
    8179                void postvisit( OffsetofExpr * offsetofExpr );
    8280                void postvisit( OffsetPackExpr * offsetPackExpr );
    83                 void postvisit( AttrExpr * attrExpr );
    8481                void postvisit( LogicalExpr * logicalExpr );
    8582                void postvisit( ConditionalExpr * conditionalExpr );
     
    10299                void addAnonConversions( const Alternative & alt );
    103100                /// Adds alternatives for member expressions, given the aggregate, conversion cost for that aggregate, and name of the member
    104                 template< typename StructOrUnionType > void addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, const std::string & name );
     101                template< typename StructOrUnionType > void addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Alternative &alt, const Cost &newCost, const std::string & name );
    105102                /// Adds alternatives for member expressions where the left side has tuple type
    106                 void addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member );
     103                void addTupleMembers( TupleType *tupleType, Expression *expr, const Alternative &alt, const Cost &newCost, Expression *member );
    107104                /// Adds alternatives for offsetof expressions, given the base type and name of the member
    108105                template< typename StructOrUnionType > void addOffsetof( StructOrUnionType *aggInst, const std::string &name );
     
    112109                /// Finds matching alternatives for a function, given a set of arguments
    113110                template<typename OutputIterator>
    114                 void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const ExplodedArgs& args, OutputIterator out );
    115                 /// Checks if assertion parameters match for a new alternative
     111                void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const ExplodedArgs_old& args, OutputIterator out );
     112                /// Sets up parameter inference for an output alternative
    116113                template< typename OutputIterator >
    117                 void inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out );
     114                void inferParameters( Alternative &newAlt, OutputIterator out );
    118115        private:
    119116                AlternativeFinder & altFinder;
     
    133130
    134131        void printAlts( const AltList &list, std::ostream &os, unsigned int indentAmt ) {
    135                 Indenter indent = { Indenter::tabsize, indentAmt };
     132                Indenter indent = { indentAmt };
    136133                for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) {
    137134                        i->print( os, indent );
     
    176173                                                selected[ mangleName ] = current;
    177174                                        } else if ( candidate->cost == mapPlace->second.candidate->cost ) {
    178                                                 PRINT(
    179                                                         std::cerr << "marking ambiguous" << std::endl;
    180                                                 )
    181                                                 mapPlace->second.isAmbiguous = true;
     175                                                // if one of the candidates contains a deleted identifier, can pick the other, since
     176                                                // deleted expressions should not be ambiguous if there is another option that is at least as good
     177                                                if ( findDeletedExpr( candidate->expr ) ) {
     178                                                        // do nothing
     179                                                        PRINT( std::cerr << "candidate is deleted" << std::endl; )
     180                                                } else if ( findDeletedExpr( mapPlace->second.candidate->expr ) ) {
     181                                                        PRINT( std::cerr << "current is deleted" << std::endl; )
     182                                                        selected[ mangleName ] = current;
     183                                                } else {
     184                                                        PRINT(
     185                                                                std::cerr << "marking ambiguous" << std::endl;
     186                                                        )
     187                                                        mapPlace->second.isAmbiguous = true;
     188                                                }
    182189                                        } else {
    183190                                                PRINT(
     
    234241        }
    235242
    236         void AlternativeFinder::find( Expression *expr, bool adjust, bool prune, bool failFast ) {
     243        void AlternativeFinder::find( Expression *expr, ResolvMode mode ) {
    237244                PassVisitor<Finder> finder( *this );
    238245                expr->accept( finder );
    239                 if ( failFast && alternatives.empty() ) {
     246                if ( mode.failFast && alternatives.empty() ) {
    240247                        PRINT(
    241248                                std::cerr << "No reasonable alternatives for expression " << expr << std::endl;
     
    243250                        SemanticError( expr, "No reasonable alternatives for expression " );
    244251                }
    245                 if ( prune ) {
     252                if ( mode.satisfyAssns || mode.prune ) {
     253                        // trim candidates just to those where the assertions resolve
     254                        // - necessary pre-requisite to pruning
     255                        AltList candidates;
     256                        std::list<std::string> errors;
     257                        for ( unsigned i = 0; i < alternatives.size(); ++i ) {
     258                                resolveAssertions( alternatives[i], indexer, candidates, errors );
     259                        }
     260                        // fail early if none such
     261                        if ( mode.failFast && candidates.empty() ) {
     262                                std::ostringstream stream;
     263                                stream << "No alternatives with satisfiable assertions for " << expr << "\n";
     264                                //        << "Alternatives with failing assertions are:\n";
     265                                // printAlts( alternatives, stream, 1 );
     266                                for ( const auto& err : errors ) {
     267                                        stream << err;
     268                                }
     269                                SemanticError( expr->location, stream.str() );
     270                        }
     271                        // reset alternatives
     272                        alternatives = std::move( candidates );
     273                }
     274                if ( mode.prune ) {
    246275                        auto oldsize = alternatives.size();
    247276                        PRINT(
     
    251280                        AltList pruned;
    252281                        pruneAlternatives( alternatives.begin(), alternatives.end(), back_inserter( pruned ) );
    253                         if ( failFast && pruned.empty() ) {
     282                        if ( mode.failFast && pruned.empty() ) {
    254283                                std::ostringstream stream;
    255284                                AltList winners;
     
    270299                }
    271300                // adjust types after pruning so that types substituted by pruneAlternatives are correctly adjusted
    272                 for ( AltList::iterator i = alternatives.begin(); i != alternatives.end(); ++i ) {
    273                         if ( adjust ) {
    274                                 adjustExprType( i->expr->get_result(), i->env, indexer );
     301                if ( mode.adjust ) {
     302                        for ( Alternative& i : alternatives ) {
     303                                adjustExprType( i.expr->get_result(), i.env, indexer );
    275304                        }
    276305                }
     
    284313
    285314        void AlternativeFinder::findWithAdjustment( Expression *expr ) {
    286                 find( expr, true );
     315                find( expr, ResolvMode::withAdjustment() );
    287316        }
    288317
    289318        void AlternativeFinder::findWithoutPrune( Expression * expr ) {
    290                 find( expr, true, false );
     319                find( expr, ResolvMode::withoutPrune() );
    291320        }
    292321
    293322        void AlternativeFinder::maybeFind( Expression * expr ) {
    294                 find( expr, true, true, false );
     323                find( expr, ResolvMode::withoutFailFast() );
    295324        }
    296325
     
    306335                }
    307336
    308                 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->result ) ) {
    309                         addAggMembers( structInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, "" );
    310                 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->result ) ) {
    311                         addAggMembers( unionInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, "" );
     337                if ( StructInstType * structInst = dynamic_cast< StructInstType* >( aggrExpr->result ) ) {
     338                        addAggMembers( structInst, aggrExpr.get(), alt, alt.cost+Cost::safe, "" );
     339                } else if ( UnionInstType * unionInst = dynamic_cast< UnionInstType* >( aggrExpr->result ) ) {
     340                        addAggMembers( unionInst, aggrExpr.get(), alt, alt.cost+Cost::safe, "" );
    312341                } // if
    313342        }
    314343
    315344        template< typename StructOrUnionType >
    316         void AlternativeFinder::Finder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, const std::string & name ) {
     345        void AlternativeFinder::Finder::addAggMembers( StructOrUnionType * aggInst, Expression * expr, const Alternative& alt, const Cost &newCost, const std::string & name ) {
    317346                std::list< Declaration* > members;
    318347                aggInst->lookup( name, members );
    319348
    320349                for ( Declaration * decl : members ) {
    321                         if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( decl ) ) {
     350                        if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType* >( decl ) ) {
    322351                                // addAnonAlternatives uses vector::push_back, which invalidates references to existing elements, so
    323352                                // can't construct in place and use vector::back
    324                                 Alternative newAlt( new MemberExpr( dwt, expr->clone() ), env, newCost );
     353                                Alternative newAlt{ alt, new MemberExpr{ dwt, expr->clone() }, newCost };
    325354                                renameTypes( newAlt.expr );
    326355                                addAnonConversions( newAlt ); // add anonymous member interpretations whenever an aggregate value type is seen as a member expression.
     
    332361        }
    333362
    334         void AlternativeFinder::Finder::addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
     363        void AlternativeFinder::Finder::addTupleMembers( TupleType * tupleType, Expression * expr, const Alternative &alt, const Cost &newCost, Expression * member ) {
    335364                if ( ConstantExpr * constantExpr = dynamic_cast< ConstantExpr * >( member ) ) {
    336365                        // get the value of the constant expression as an int, must be between 0 and the length of the tuple type to have meaning
    337                         // xxx - this should be improved by memoizing the value of constant exprs
    338                         // during parsing and reusing that information here.
    339                         std::stringstream ss( constantExpr->get_constant()->get_value() );
    340                         int val = 0;
     366                        auto val = constantExpr->intValue();
    341367                        std::string tmp;
    342                         if ( ss >> val && ! (ss >> tmp) ) {
    343                                 if ( val >= 0 && (unsigned int)val < tupleType->size() ) {
    344                                         alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) );
    345                                 } // if
     368                        if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {
     369                                alternatives.push_back( Alternative{
     370                                        alt, new TupleIndexExpr( expr->clone(), val ), newCost } );
    346371                        } // if
    347                 } else if ( NameExpr * nameExpr = dynamic_cast< NameExpr * >( member ) ) {
    348                         // xxx - temporary hack until 0/1 are int constants
    349                         if ( nameExpr->get_name() == "0" || nameExpr->get_name() == "1" ) {
    350                                 std::stringstream ss( nameExpr->get_name() );
    351                                 int val;
    352                                 ss >> val;
    353                                 alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) );
    354                         }
    355372                } // if
    356373        }
    357374
    358         void AlternativeFinder::Finder::postvisit( ApplicationExpr *applicationExpr ) {
    359                 alternatives.push_back( Alternative( applicationExpr->clone(), env, Cost::zero ) );
    360         }
    361 
    362         Cost computeConversionCost( Type * actualType, Type * formalType, const SymTab::Indexer &indexer, const TypeEnvironment & env ) {
     375        void AlternativeFinder::Finder::postvisit( ApplicationExpr * applicationExpr ) {
     376                alternatives.push_back( Alternative{ applicationExpr->clone(), env } );
     377        }
     378
     379        Cost computeConversionCost( Type * actualType, Type * formalType, bool actualIsLvalue,
     380                        const SymTab::Indexer &indexer, const TypeEnvironment & env ) {
    363381                PRINT(
    364382                        std::cerr << std::endl << "converting ";
     
    370388                        std::cerr << std::endl;
    371389                )
    372                 Cost convCost = conversionCost( actualType, formalType, indexer, env );
     390                Cost convCost = conversionCost( actualType, formalType, actualIsLvalue, indexer, env );
    373391                PRINT(
    374392                        std::cerr << std::endl << "cost is " << convCost << std::endl;
     
    385403
    386404        Cost computeExpressionConversionCost( Expression *& actualExpr, Type * formalType, const SymTab::Indexer &indexer, const TypeEnvironment & env ) {
    387                 Cost convCost = computeConversionCost( actualExpr->result, formalType, indexer, env );
     405                Cost convCost = computeConversionCost(
     406                        actualExpr->result, formalType, actualExpr->get_lvalue(), indexer, env );
    388407
    389408                // if there is a non-zero conversion cost, ignoring poly cost, then the expression requires conversion.
     
    413432        Cost computeApplicationConversionCost( Alternative &alt, const SymTab::Indexer &indexer ) {
    414433                ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( alt.expr );
    415                 PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
    416                 FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->get_base() );
     434                PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->function->result );
     435                FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->base );
    417436
    418437                Cost convCost = Cost::zero;
    419                 std::list< DeclarationWithType* >& formals = function->get_parameters();
     438                std::list< DeclarationWithType* >& formals = function->parameters;
    420439                std::list< DeclarationWithType* >::iterator formal = formals.begin();
    421                 std::list< Expression* >& actuals = appExpr->get_args();
    422 
    423                 for ( std::list< Expression* >::iterator actualExpr = actuals.begin(); actualExpr != actuals.end(); ++actualExpr ) {
    424                         Type * actualType = (*actualExpr)->get_result();
     440                std::list< Expression* >& actuals = appExpr->args;
     441
     442                for ( Expression*& actualExpr : actuals ) {
     443                        Type * actualType = actualExpr->result;
    425444                        PRINT(
    426445                                std::cerr << "actual expression:" << std::endl;
    427                                 (*actualExpr)->print( std::cerr, 8 );
     446                                actualExpr->print( std::cerr, 8 );
    428447                                std::cerr << "--- results are" << std::endl;
    429448                                actualType->print( std::cerr, 8 );
    430449                        )
    431450                        if ( formal == formals.end() ) {
    432                                 if ( function->get_isVarArgs() ) {
     451                                if ( function->isVarArgs ) {
    433452                                        convCost.incUnsafe();
    434453                                        PRINT( std::cerr << "end of formals with varargs function: inc unsafe: " << convCost << std::endl; ; )
    435454                                        // convert reference-typed expressions to value-typed expressions
    436                                         referenceToRvalueConversion( *actualExpr, convCost );
     455                                        referenceToRvalueConversion( actualExpr, convCost );
    437456                                        continue;
    438457                                } else {
     
    440459                                }
    441460                        }
     461                        if ( DefaultArgExpr * def = dynamic_cast< DefaultArgExpr * >( actualExpr ) ) {
     462                                // default arguments should be free - don't include conversion cost.
     463                                // Unwrap them here because they are not relevant to the rest of the system.
     464                                actualExpr = def->expr;
     465                                ++formal;
     466                                continue;
     467                        }
     468                        // mark conversion cost to formal and also specialization cost of formal type
    442469                        Type * formalType = (*formal)->get_type();
    443                         convCost += computeExpressionConversionCost( *actualExpr, formalType, indexer, alt.env );
     470                        convCost += computeExpressionConversionCost( actualExpr, formalType, indexer, alt.env );
     471                        convCost.decSpec( specCost( formalType ) );
    444472                        ++formal; // can't be in for-loop update because of the continue
    445473                }
     
    448476                }
    449477
    450                 for ( InferredParams::const_iterator assert = appExpr->get_inferParams().begin(); assert != appExpr->get_inferParams().end(); ++assert ) {
    451                         convCost += computeConversionCost( assert->second.actualType, assert->second.formalType, indexer, alt.env );
     478                // specialization cost of return types can't be accounted for directly, it disables
     479                // otherwise-identical calls, like this example based on auto-newline in the I/O lib:
     480                //
     481                //   forall(otype OS) {
     482                //     void ?|?(OS&, int);  // with newline
     483                //     OS&  ?|?(OS&, int);  // no newline, always chosen due to more specialization
     484                //   }
     485
     486                // mark type variable and specialization cost of forall clause
     487                convCost.incVar( function->forall.size() );
     488                for ( TypeDecl* td : function->forall ) {
     489                        convCost.decSpec( td->assertions.size() );
    452490                }
    453491
     
    462500                                needAssertions[ *assert ].isUsed = true;
    463501                        }
    464 ///     needAssertions.insert( needAssertions.end(), (*tyvar)->get_assertions().begin(), (*tyvar)->get_assertions().end() );
    465                 }
    466         }
    467 
    468         static const int recursionLimit = /*10*/ 4;  ///< Limit to depth of recursion satisfaction
    469 
    470         void addToIndexer( AssertionSet &assertSet, SymTab::Indexer &indexer ) {
    471                 for ( AssertionSet::iterator i = assertSet.begin(); i != assertSet.end(); ++i ) {
    472                         if ( i->second.isUsed ) {
    473                                 indexer.addId( i->first );
    474                         }
    475                 }
    476         }
    477 
    478         template< typename ForwardIterator, typename OutputIterator >
    479         void inferRecursive( ForwardIterator begin, ForwardIterator end, const Alternative &newAlt, OpenVarSet &openVars, const SymTab::Indexer &decls, const AssertionSet &newNeed, int level, const SymTab::Indexer &indexer, OutputIterator out ) {
    480                 if ( begin == end ) {
    481                         if ( newNeed.empty() ) {
    482                                 PRINT(
    483                                         std::cerr << "all assertions satisfied, output alternative: ";
    484                                         newAlt.print( std::cerr );
    485                                         std::cerr << std::endl;
    486                                 );
    487                                 *out++ = newAlt;
    488                                 return;
    489                         } else if ( level >= recursionLimit ) {
    490                                 SemanticError( newAlt.expr->location, "Too many recursive assertions" );
    491                         } else {
    492                                 AssertionSet newerNeed;
    493                                 PRINT(
    494                                         std::cerr << "recursing with new set:" << std::endl;
    495                                         printAssertionSet( newNeed, std::cerr, 8 );
    496                                 )
    497                                 inferRecursive( newNeed.begin(), newNeed.end(), newAlt, openVars, decls, newerNeed, level+1, indexer, out );
    498                                 return;
    499                         }
    500                 }
    501 
    502                 ForwardIterator cur = begin++;
    503                 if ( ! cur->second.isUsed ) {
    504                         inferRecursive( begin, end, newAlt, openVars, decls, newNeed, level, indexer, out );
    505                         return; // xxx - should this continue? previously this wasn't here, and it looks like it should be
    506                 }
    507                 DeclarationWithType *curDecl = cur->first;
    508 
    509                 PRINT(
    510                         std::cerr << "inferRecursive: assertion is ";
    511                         curDecl->print( std::cerr );
    512                         std::cerr << std::endl;
    513                 )
    514                 std::list< SymTab::Indexer::IdData > candidates;
    515                 decls.lookupId( curDecl->get_name(), candidates );
    516 ///   if ( candidates.empty() ) { std::cerr << "no candidates!" << std::endl; }
    517                 for ( const auto & data : candidates ) {
    518                         DeclarationWithType * candidate = data.id;
    519                         PRINT(
    520                                 std::cerr << "inferRecursive: candidate is ";
    521                                 candidate->print( std::cerr );
    522                                 std::cerr << std::endl;
    523                         )
    524 
    525                         AssertionSet newHave, newerNeed( newNeed );
    526                         TypeEnvironment newEnv( newAlt.env );
    527                         OpenVarSet newOpenVars( openVars );
    528                         Type *adjType = candidate->get_type()->clone();
    529                         adjustExprType( adjType, newEnv, indexer );
    530                         renameTyVars( adjType );
    531                         PRINT(
    532                                 std::cerr << "unifying ";
    533                                 curDecl->get_type()->print( std::cerr );
    534                                 std::cerr << " with ";
    535                                 adjType->print( std::cerr );
    536                                 std::cerr << std::endl;
    537                         )
    538                         if ( unify( curDecl->get_type(), adjType, newEnv, newerNeed, newHave, newOpenVars, indexer ) ) {
    539                                 PRINT(
    540                                         std::cerr << "success!" << std::endl;
    541                                 )
    542                                 SymTab::Indexer newDecls( decls );
    543                                 addToIndexer( newHave, newDecls );
    544                                 Alternative newerAlt( newAlt );
    545                                 newerAlt.env = newEnv;
    546                                 assertf( candidate->get_uniqueId(), "Assertion candidate does not have a unique ID: %s", toString( candidate ).c_str() );
    547 
    548                                 // everything with an empty idChain was pulled in by the current assertion.
    549                                 // add current assertion's idChain + current assertion's ID so that the correct inferParameters can be found.
    550                                 for ( auto & a : newerNeed ) {
    551                                         if ( a.second.idChain.empty() ) {
    552                                                 a.second.idChain = cur->second.idChain;
    553                                                 a.second.idChain.push_back( curDecl->get_uniqueId() );
    554                                         }
    555                                 }
    556 
    557                                 Expression *varExpr = data.combine( newerAlt.cvtCost );
    558                                 delete varExpr->get_result();
    559                                 varExpr->set_result( adjType->clone() );
    560                                 PRINT(
    561                                         std::cerr << "satisfying assertion " << curDecl->get_uniqueId() << " ";
    562                                         curDecl->print( std::cerr );
    563                                         std::cerr << " with declaration " << candidate->get_uniqueId() << " ";
    564                                         candidate->print( std::cerr );
    565                                         std::cerr << std::endl;
    566                                 )
    567                                 // follow the current assertion's ID chain to find the correct set of inferred parameters to add the candidate to (i.e. the set of inferred parameters belonging to the entity which requested the assertion parameter).
    568                                 InferredParams * inferParameters = &newerAlt.expr->get_inferParams();
    569                                 for ( UniqueId id : cur->second.idChain ) {
    570                                         inferParameters = (*inferParameters)[ id ].inferParams.get();
    571                                 }
    572                                 // XXX: this is a memory leak, but adjType can't be deleted because it might contain assertions
    573                                 (*inferParameters)[ curDecl->get_uniqueId() ] = ParamEntry( candidate->get_uniqueId(), adjType->clone(), curDecl->get_type()->clone(), varExpr );
    574                                 inferRecursive( begin, end, newerAlt, newOpenVars, newDecls, newerNeed, level, indexer, out );
    575                         } else {
    576                                 delete adjType;
    577                         }
    578                 }
    579         }
     502                }
     503        }
     504
     505        /// Unique identifier for matching expression resolutions to their requesting expression (located in CandidateFinder.cpp)
     506        extern UniqueId globalResnSlot;
    580507
    581508        template< typename OutputIterator >
    582         void AlternativeFinder::Finder::inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out ) {
    583 //      PRINT(
    584 //          std::cerr << "inferParameters: assertions needed are" << std::endl;
    585 //          printAll( need, std::cerr, 8 );
    586 //          )
    587                 SymTab::Indexer decls( indexer );
    588                 // PRINT(
    589                 //      std::cerr << "============= original indexer" << std::endl;
    590                 //      indexer.print( std::cerr );
    591                 //      std::cerr << "============= new indexer" << std::endl;
    592                 //      decls.print( std::cerr );
    593                 // )
    594                 addToIndexer( have, decls );
    595                 AssertionSet newNeed;
    596                 PRINT(
    597                         std::cerr << "env is: " << std::endl;
    598                         newAlt.env.print( std::cerr, 0 );
    599                         std::cerr << std::endl;
    600                 )
    601 
    602                 inferRecursive( need.begin(), need.end(), newAlt, openVars, decls, newNeed, 0, indexer, out );
    603 //      PRINT(
    604 //          std::cerr << "declaration 14 is ";
    605 //          Declaration::declFromId
    606 //          *out++ = newAlt;
    607 //          )
     509        void AlternativeFinder::Finder::inferParameters( Alternative &newAlt, OutputIterator out ) {
     510                // Set need bindings for any unbound assertions
     511                UniqueId crntResnSlot = 0;  // matching ID for this expression's assertions
     512                for ( auto& assn : newAlt.need ) {
     513                        // skip already-matched assertions
     514                        if ( assn.info.resnSlot != 0 ) continue;
     515                        // assign slot for expression if needed
     516                        if ( crntResnSlot == 0 ) { crntResnSlot = ++globalResnSlot; }
     517                        // fix slot to assertion
     518                        assn.info.resnSlot = crntResnSlot;
     519                }
     520                // pair slot to expression
     521                if ( crntResnSlot != 0 ) { newAlt.expr->resnSlots.push_back( crntResnSlot ); }
     522
     523                // add to output list, assertion resolution is deferred
     524                *out++ = newAlt;
    608525        }
    609526
     
    611528        ConstantExpr* getDefaultValue( Initializer* init ) {
    612529                if ( SingleInit* si = dynamic_cast<SingleInit*>( init ) ) {
    613                         if ( CastExpr* ce = dynamic_cast<CastExpr*>( si->get_value() ) ) {
    614                                 return dynamic_cast<ConstantExpr*>( ce->get_arg() );
     530                        if ( CastExpr* ce = dynamic_cast<CastExpr*>( si->value ) ) {
     531                                return dynamic_cast<ConstantExpr*>( ce->arg );
     532                        } else {
     533                                return dynamic_cast<ConstantExpr*>( si->value );
    615534                        }
    616535                }
     
    659578
    660579                /// Gets the list of exploded alternatives for this pack
    661                 const ExplodedActual& getExpl( const ExplodedArgs& args ) const {
     580                const ExplodedActual& getExpl( const ExplodedArgs_old& args ) const {
    662581                        return args[nextArg-1][explAlt];
    663582                }
     
    683602        /// Instantiates an argument to match a formal, returns false if no results left
    684603        bool instantiateArgument( Type* formalType, Initializer* initializer,
    685                         const ExplodedArgs& args, std::vector<ArgPack>& results, std::size_t& genStart,
     604                        const ExplodedArgs_old& args, std::vector<ArgPack>& results, std::size_t& genStart,
    686605                        const SymTab::Indexer& indexer, unsigned nTuples = 0 ) {
    687606                if ( TupleType * tupleType = dynamic_cast<TupleType*>( formalType ) ) {
     
    873792                                                                indexer ) ) {
    874793                                                        results.emplace_back(
    875                                                                 i, cnstExpr, move(env), move(need), move(have),
     794                                                                i, new DefaultArgExpr( cnstExpr ), move(env), move(need), move(have),
    876795                                                                move(openVars), nextArg, nTuples );
    877796                                                }
     
    944863                }
    945864                // build and validate new alternative
    946                 Alternative newAlt( appExpr, result.env, cost );
     865                Alternative newAlt{ appExpr, result.env, result.openVars, result.need, cost };
    947866                PRINT(
    948867                        std::cerr << "instantiate function success: " << appExpr << std::endl;
     
    950869                        printAssertionSet( result.need, std::cerr, 8 );
    951870                )
    952                 inferParameters( result.need, result.have, newAlt, result.openVars, out );
     871                inferParameters( newAlt, out );
    953872        }
    954873
    955874        template<typename OutputIterator>
    956875        void AlternativeFinder::Finder::makeFunctionAlternatives( const Alternative &func,
    957                         FunctionType *funcType, const ExplodedArgs &args, OutputIterator out ) {
     876                        FunctionType *funcType, const ExplodedArgs_old &args, OutputIterator out ) {
    958877                OpenVarSet funcOpenVars;
    959878                AssertionSet funcNeed, funcHave;
     
    1065984                funcFinder.findWithAdjustment( untypedExpr->function );
    1066985                // if there are no function alternatives, then proceeding is a waste of time.
     986                // xxx - findWithAdjustment throws, so this check and others like it shouldn't be necessary.
    1067987                if ( funcFinder.alternatives.empty() ) return;
    1068988
     
    10861006
    10871007                // pre-explode arguments
    1088                 ExplodedArgs argExpansions;
     1008                ExplodedArgs_old argExpansions;
    10891009                argExpansions.reserve( argAlternatives.size() );
    10901010
     
    10921012                        argExpansions.emplace_back();
    10931013                        auto& argE = argExpansions.back();
    1094                         argE.reserve( arg.alternatives.size() );
     1014                        // argE.reserve( arg.alternatives.size() );
    10951015
    10961016                        for ( const Alternative& actual : arg ) {
     
    11781098                                std::cerr << "bindings are:" << std::endl;
    11791099                                withFunc.env.print( std::cerr, 8 );
     1100                                std::cerr << "cost is: " << withFunc.cost << std::endl;
    11801101                                std::cerr << "cost of conversion is:" << cvtCost << std::endl;
    11811102                        )
     
    11931114
    11941115                // function may return struct or union value, in which case we need to add alternatives
    1195                 // for implicitconversions to each of the anonymous members, must happen after findMinCost
     1116                // for implicit conversions to each of the anonymous members, must happen after findMinCost
    11961117                // since anon conversions are never the cheapest expression
    11971118                for ( const Alternative & alt : winners ) {
     
    12161137        bool isLvalue( Expression *expr ) {
    12171138                // xxx - recurse into tuples?
    1218                 return expr->result && ( expr->result->get_lvalue() || dynamic_cast< ReferenceType * >( expr->result ) );
     1139                return expr->result && ( expr->get_lvalue() || dynamic_cast< ReferenceType * >( expr->result ) );
    12191140        }
    12201141
     
    12251146                        if ( isLvalue( alt.expr ) ) {
    12261147                                alternatives.push_back(
    1227                                         Alternative{ new AddressExpr( alt.expr->clone() ), alt.env, alt.cost } );
     1148                                        Alternative{ alt, new AddressExpr( alt.expr->clone() ), alt.cost } );
    12281149                        } // if
    12291150                } // for
     
    12311152
    12321153        void AlternativeFinder::Finder::postvisit( LabelAddressExpr * expr ) {
    1233                 alternatives.push_back( Alternative{ expr->clone(), env, Cost::zero } );
     1154                alternatives.push_back( Alternative{ expr->clone(), env } );
    12341155        }
    12351156
     
    12671188                assert( toType );
    12681189                toType = resolveTypeof( toType, indexer );
     1190                assert(!dynamic_cast<TypeofType *>(toType));
    12691191                SymTab::validateType( toType, &indexer );
    12701192                adjustExprType( toType, env, indexer );
     
    12761198                AltList candidates;
    12771199                for ( Alternative & alt : finder.alternatives ) {
    1278                         AssertionSet needAssertions, haveAssertions;
    1279                         OpenVarSet openVars;
     1200                        AssertionSet needAssertions( alt.need.begin(), alt.need.end() );
     1201                        AssertionSet haveAssertions;
     1202                        OpenVarSet openVars{ alt.openVars };
    12801203
    12811204                        alt.env.extractOpenVars( openVars );
     
    12921215                        unify( castExpr->result, alt.expr->result, alt.env, needAssertions,
    12931216                                haveAssertions, openVars, indexer );
    1294                         Cost thisCost = castCost( alt.expr->result, castExpr->result, indexer,
    1295                                 alt.env );
     1217                        Cost thisCost = castCost( alt.expr->result, castExpr->result, alt.expr->get_lvalue(),
     1218                                indexer, alt.env );
    12961219                        PRINT(
    12971220                                std::cerr << "working on cast with result: " << castExpr->result << std::endl;
     
    13051228                                // count one safe conversion for each value that is thrown away
    13061229                                thisCost.incSafe( discardedValues );
    1307                                 Alternative newAlt( restructureCast( alt.expr->clone(), toType, castExpr->isGenerated ), alt.env,
    1308                                         alt.cost, thisCost );
    1309                                 inferParameters( needAssertions, haveAssertions, newAlt, openVars,
    1310                                         back_inserter( candidates ) );
     1230                                Alternative newAlt{
     1231                                        restructureCast( alt.expr->clone(), toType, castExpr->isGenerated ),
     1232                                        alt.env, openVars, needAssertions, alt.cost, alt.cost + thisCost };
     1233                                inferParameters( newAlt, back_inserter( candidates ) );
    13111234                        } // if
    13121235                } // for
     
    13211244
    13221245        void AlternativeFinder::Finder::postvisit( VirtualCastExpr * castExpr ) {
    1323                 assertf( castExpr->get_result(), "Implicate virtual cast targets not yet supported." );
     1246                assertf( castExpr->get_result(), "Implicit virtual cast targets not yet supported." );
    13241247                AlternativeFinder finder( indexer, env );
    13251248                // don't prune here, since it's guaranteed all alternatives will have the same type
    13261249                finder.findWithoutPrune( castExpr->get_arg() );
    13271250                for ( Alternative & alt : finder.alternatives ) {
    1328                         alternatives.push_back( Alternative(
    1329                                 new VirtualCastExpr( alt.expr->clone(), castExpr->get_result()->clone() ),
    1330                                 alt.env, alt.cost ) );
     1251                        alternatives.push_back( Alternative{
     1252                                alt, new VirtualCastExpr{ alt.expr->clone(), castExpr->get_result()->clone() },
     1253                                alt.cost } );
    13311254                }
    13321255        }
     
    13351258                /// Gets name from untyped member expression (member must be NameExpr)
    13361259                const std::string& get_member_name( UntypedMemberExpr *memberExpr ) {
     1260                        if ( dynamic_cast< ConstantExpr * >( memberExpr->get_member() ) ) {
     1261                                SemanticError( memberExpr, "Indexed access to struct fields unsupported: " );
     1262                        } // if
    13371263                        NameExpr * nameExpr = dynamic_cast< NameExpr * >( memberExpr->get_member() );
    13381264                        assert( nameExpr );
     
    13531279                        // find member of the given type
    13541280                        if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) {
    1355                                 addAggMembers( structInst, aggrExpr, cost, agg->env, get_member_name(memberExpr) );
     1281                                addAggMembers( structInst, aggrExpr, *agg, cost, get_member_name(memberExpr) );
    13561282                        } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) {
    1357                                 addAggMembers( unionInst, aggrExpr, cost, agg->env, get_member_name(memberExpr) );
     1283                                addAggMembers( unionInst, aggrExpr, *agg, cost, get_member_name(memberExpr) );
    13581284                        } else if ( TupleType * tupleType = dynamic_cast< TupleType * >( aggrExpr->get_result() ) ) {
    1359                                 addTupleMembers( tupleType, aggrExpr, cost, agg->env, memberExpr->get_member() );
     1285                                addTupleMembers( tupleType, aggrExpr, *agg, cost, memberExpr->get_member() );
    13601286                        } // if
    13611287                } // for
     
    13631289
    13641290        void AlternativeFinder::Finder::postvisit( MemberExpr *memberExpr ) {
    1365                 alternatives.push_back( Alternative( memberExpr->clone(), env, Cost::zero ) );
     1291                alternatives.push_back( Alternative{ memberExpr->clone(), env } );
    13661292        }
    13671293
     
    13761302                        // addAnonAlternatives uses vector::push_back, which invalidates references to existing elements, so
    13771303                        // can't construct in place and use vector::back
    1378                         Alternative newAlt( newExpr, env, Cost::zero, cost );
     1304                        Alternative newAlt{ newExpr, env, OpenVarSet{}, AssertionList{}, Cost::zero, cost };
    13791305                        PRINT(
    13801306                                std::cerr << "decl is ";
     
    13941320                // not sufficient to clone here, because variable's type may have changed
    13951321                // since the VariableExpr was originally created.
    1396                 alternatives.push_back( Alternative( new VariableExpr( variableExpr->var ), env, Cost::zero ) );
     1322                alternatives.push_back( Alternative{ new VariableExpr{ variableExpr->var }, env } );
    13971323        }
    13981324
    13991325        void AlternativeFinder::Finder::postvisit( ConstantExpr *constantExpr ) {
    1400                 alternatives.push_back( Alternative( constantExpr->clone(), env, Cost::zero ) );
     1326                alternatives.push_back( Alternative{ constantExpr->clone(), env } );
    14011327        }
    14021328
     
    14041330                if ( sizeofExpr->get_isType() ) {
    14051331                        Type * newType = sizeofExpr->get_type()->clone();
    1406                         alternatives.push_back( Alternative( new SizeofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
     1332                        alternatives.push_back( Alternative{
     1333                                new SizeofExpr{ resolveTypeof( newType, indexer ) }, env } );
    14071334                } else {
    14081335                        // find all alternatives for the argument to sizeof
     
    14181345                        Alternative &choice = winners.front();
    14191346                        referenceToRvalueConversion( choice.expr, choice.cost );
    1420                         alternatives.push_back( Alternative( new SizeofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
     1347                        alternatives.push_back( Alternative{
     1348                                choice, new SizeofExpr( choice.expr->clone() ), Cost::zero } );
    14211349                } // if
    14221350        }
     
    14251353                if ( alignofExpr->get_isType() ) {
    14261354                        Type * newType = alignofExpr->get_type()->clone();
    1427                         alternatives.push_back( Alternative( new AlignofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
     1355                        alternatives.push_back( Alternative{
     1356                                new AlignofExpr{ resolveTypeof( newType, indexer ) }, env } );
    14281357                } else {
    14291358                        // find all alternatives for the argument to sizeof
     
    14391368                        Alternative &choice = winners.front();
    14401369                        referenceToRvalueConversion( choice.expr, choice.cost );
    1441                         alternatives.push_back( Alternative( new AlignofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
     1370                        alternatives.push_back( Alternative{
     1371                                choice, new AlignofExpr{ choice.expr->clone() }, Cost::zero } );
    14421372                } // if
    14431373        }
     
    14491379                for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) {
    14501380                        if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) {
    1451                                 alternatives.push_back( Alternative( new OffsetofExpr( aggInst->clone(), dwt ), env, Cost::zero ) );
     1381                                alternatives.push_back( Alternative{
     1382                                        new OffsetofExpr{ aggInst->clone(), dwt }, env } );
    14521383                                renameTypes( alternatives.back().expr );
    14531384                        } else {
     
    14681399
    14691400        void AlternativeFinder::Finder::postvisit( OffsetofExpr *offsetofExpr ) {
    1470                 alternatives.push_back( Alternative( offsetofExpr->clone(), env, Cost::zero ) );
     1401                alternatives.push_back( Alternative{ offsetofExpr->clone(), env } );
    14711402        }
    14721403
    14731404        void AlternativeFinder::Finder::postvisit( OffsetPackExpr *offsetPackExpr ) {
    1474                 alternatives.push_back( Alternative( offsetPackExpr->clone(), env, Cost::zero ) );
    1475         }
    1476 
    1477         namespace {
    1478                 void resolveAttr( SymTab::Indexer::IdData data, FunctionType *function, Type *argType, const TypeEnvironment &env, AlternativeFinder & finder ) {
    1479                         // assume no polymorphism
    1480                         // assume no implicit conversions
    1481                         assert( function->get_parameters().size() == 1 );
    1482                         PRINT(
    1483                                 std::cerr << "resolvAttr: funcDecl is ";
    1484                                 data.id->print( std::cerr );
    1485                                 std::cerr << " argType is ";
    1486                                 argType->print( std::cerr );
    1487                                 std::cerr << std::endl;
    1488                         )
    1489                         const SymTab::Indexer & indexer = finder.get_indexer();
    1490                         AltList & alternatives = finder.get_alternatives();
    1491                         if ( typesCompatibleIgnoreQualifiers( argType, function->get_parameters().front()->get_type(), indexer, env ) ) {
    1492                                 Cost cost = Cost::zero;
    1493                                 Expression * newExpr = data.combine( cost );
    1494                                 alternatives.push_back( Alternative( new AttrExpr( newExpr, argType->clone() ), env, Cost::zero, cost ) );
    1495                                 for ( DeclarationWithType * retVal : function->returnVals ) {
    1496                                         alternatives.back().expr->result = retVal->get_type()->clone();
    1497                                 } // for
    1498                         } // if
    1499                 }
    1500         }
    1501 
    1502         void AlternativeFinder::Finder::postvisit( AttrExpr *attrExpr ) {
    1503                 // assume no 'pointer-to-attribute'
    1504                 NameExpr *nameExpr = dynamic_cast< NameExpr* >( attrExpr->get_attr() );
    1505                 assert( nameExpr );
    1506                 std::list< SymTab::Indexer::IdData > attrList;
    1507                 indexer.lookupId( nameExpr->get_name(), attrList );
    1508                 if ( attrExpr->get_isType() || attrExpr->get_expr() ) {
    1509                         for ( auto & data : attrList ) {
    1510                                 DeclarationWithType * id = data.id;
    1511                                 // check if the type is function
    1512                                 if ( FunctionType *function = dynamic_cast< FunctionType* >( id->get_type() ) ) {
    1513                                         // assume exactly one parameter
    1514                                         if ( function->get_parameters().size() == 1 ) {
    1515                                                 if ( attrExpr->get_isType() ) {
    1516                                                         resolveAttr( data, function, attrExpr->get_type(), env, altFinder);
    1517                                                 } else {
    1518                                                         AlternativeFinder finder( indexer, env );
    1519                                                         finder.find( attrExpr->get_expr() );
    1520                                                         for ( AltList::iterator choice = finder.alternatives.begin(); choice != finder.alternatives.end(); ++choice ) {
    1521                                                                 if ( choice->expr->get_result()->size() == 1 ) {
    1522                                                                         resolveAttr(data, function, choice->expr->get_result(), choice->env, altFinder );
    1523                                                                 } // fi
    1524                                                         } // for
    1525                                                 } // if
    1526                                         } // if
    1527                                 } // if
    1528                         } // for
    1529                 } else {
    1530                         for ( auto & data : attrList ) {
    1531                                 Cost cost = Cost::zero;
    1532                                 Expression * newExpr = data.combine( cost );
    1533                                 alternatives.push_back( Alternative( newExpr, env, Cost::zero, cost ) );
    1534                                 renameTypes( alternatives.back().expr );
    1535                         } // for
    1536                 } // if
    1537         }
    1538 
    1539         void AlternativeFinder::Finder::postvisit( LogicalExpr *logicalExpr ) {
     1405                alternatives.push_back( Alternative{ offsetPackExpr->clone(), env } );
     1406        }
     1407
     1408        void AlternativeFinder::Finder::postvisit( LogicalExpr * logicalExpr ) {
    15401409                AlternativeFinder firstFinder( indexer, env );
    15411410                firstFinder.findWithAdjustment( logicalExpr->get_arg1() );
     
    15461415                for ( const Alternative & first : firstFinder.alternatives ) {
    15471416                        for ( const Alternative & second : secondFinder.alternatives ) {
    1548                                 TypeEnvironment compositeEnv;
    1549                                 compositeEnv.simpleCombine( first.env );
     1417                                TypeEnvironment compositeEnv{ first.env };
    15501418                                compositeEnv.simpleCombine( second.env );
    1551 
    1552                                 LogicalExpr *newExpr = new LogicalExpr( first.expr->clone(), second.expr->clone(), logicalExpr->get_isAnd() );
    1553                                 alternatives.push_back( Alternative( newExpr, compositeEnv, first.cost + second.cost ) );
     1419                                OpenVarSet openVars{ first.openVars };
     1420                                mergeOpenVars( openVars, second.openVars );
     1421                                AssertionSet need;
     1422                                cloneAll( first.need, need );
     1423                                cloneAll( second.need, need );
     1424
     1425                                LogicalExpr *newExpr = new LogicalExpr{
     1426                                        first.expr->clone(), second.expr->clone(), logicalExpr->get_isAnd() };
     1427                                alternatives.push_back( Alternative{
     1428                                        newExpr, std::move(compositeEnv), std::move(openVars),
     1429                                        AssertionList( need.begin(), need.end() ), first.cost + second.cost } );
    15541430                        }
    15551431                }
     
    15721448                        for ( const Alternative & second : secondFinder.alternatives ) {
    15731449                                for ( const Alternative & third : thirdFinder.alternatives ) {
    1574                                         TypeEnvironment compositeEnv;
    1575                                         compositeEnv.simpleCombine( first.env );
     1450                                        TypeEnvironment compositeEnv{ first.env };
    15761451                                        compositeEnv.simpleCombine( second.env );
    15771452                                        compositeEnv.simpleCombine( third.env );
     1453                                        OpenVarSet openVars{ first.openVars };
     1454                                        mergeOpenVars( openVars, second.openVars );
     1455                                        mergeOpenVars( openVars, third.openVars );
     1456                                        AssertionSet need;
     1457                                        cloneAll( first.need, need );
     1458                                        cloneAll( second.need, need );
     1459                                        cloneAll( third.need, need );
     1460                                        AssertionSet have;
    15781461
    15791462                                        // unify true and false types, then infer parameters to produce new alternatives
    1580                                         OpenVarSet openVars;
    1581                                         AssertionSet needAssertions, haveAssertions;
    1582                                         Alternative newAlt( 0, compositeEnv, first.cost + second.cost + third.cost );
    15831463                                        Type* commonType = nullptr;
    1584                                         if ( unify( second.expr->result, third.expr->result, newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
    1585                                                 ConditionalExpr *newExpr = new ConditionalExpr( first.expr->clone(), second.expr->clone(), third.expr->clone() );
     1464                                        if ( unify( second.expr->result, third.expr->result, compositeEnv,
     1465                                                        need, have, openVars, indexer, commonType ) ) {
     1466                                                ConditionalExpr *newExpr = new ConditionalExpr{
     1467                                                        first.expr->clone(), second.expr->clone(), third.expr->clone() };
    15861468                                                newExpr->result = commonType ? commonType : second.expr->result->clone();
    15871469                                                // convert both options to the conditional result type
    1588                                                 newAlt.cost += computeExpressionConversionCost( newExpr->arg2, newExpr->result, indexer, newAlt.env );
    1589                                                 newAlt.cost += computeExpressionConversionCost( newExpr->arg3, newExpr->result, indexer, newAlt.env );
    1590                                                 newAlt.expr = newExpr;
    1591                                                 inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
     1470                                                Cost cost = first.cost + second.cost + third.cost;
     1471                                                cost += computeExpressionConversionCost(
     1472                                                        newExpr->arg2, newExpr->result, indexer, compositeEnv );
     1473                                                cost += computeExpressionConversionCost(
     1474                                                        newExpr->arg3, newExpr->result, indexer, compositeEnv );
     1475                                                // output alternative
     1476                                                Alternative newAlt{
     1477                                                        newExpr, std::move(compositeEnv), std::move(openVars),
     1478                                                        AssertionList( need.begin(), need.end() ), cost };
     1479                                                inferParameters( newAlt, back_inserter( alternatives ) );
    15921480                                        } // if
    15931481                                } // for
     
    16021490                secondFinder.findWithAdjustment( commaExpr->get_arg2() );
    16031491                for ( const Alternative & alt : secondFinder.alternatives ) {
    1604                         alternatives.push_back( Alternative( new CommaExpr( newFirstArg->clone(), alt.expr->clone() ), alt.env, alt.cost ) );
     1492                        alternatives.push_back( Alternative{
     1493                                alt, new CommaExpr{ newFirstArg->clone(), alt.expr->clone() }, alt.cost } );
    16051494                } // for
    16061495                delete newFirstArg;
     
    16171506                for ( const Alternative & first : firstFinder.alternatives ) {
    16181507                        for ( const Alternative & second : secondFinder.alternatives ) {
    1619                                 TypeEnvironment compositeEnv;
    1620                                 compositeEnv.simpleCombine( first.env );
     1508                                TypeEnvironment compositeEnv{ first.env };
    16211509                                compositeEnv.simpleCombine( second.env );
    1622                                 OpenVarSet openVars;
    1623                                 AssertionSet needAssertions, haveAssertions;
    1624                                 Alternative newAlt( 0, compositeEnv, first.cost + second.cost );
     1510                                OpenVarSet openVars{ first.openVars };
     1511                                mergeOpenVars( openVars, second.openVars );
     1512                                AssertionSet need;
     1513                                cloneAll( first.need, need );
     1514                                cloneAll( second.need, need );
     1515                                AssertionSet have;
     1516
    16251517                                Type* commonType = nullptr;
    1626                                 if ( unify( first.expr->result, second.expr->result, newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
    1627                                         RangeExpr * newExpr = new RangeExpr( first.expr->clone(), second.expr->clone() );
     1518                                if ( unify( first.expr->result, second.expr->result, compositeEnv, need, have,
     1519                                                openVars, indexer, commonType ) ) {
     1520                                        RangeExpr * newExpr =
     1521                                                new RangeExpr{ first.expr->clone(), second.expr->clone() };
    16281522                                        newExpr->result = commonType ? commonType : first.expr->result->clone();
    1629                                         newAlt.expr = newExpr;
    1630                                         inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
     1523                                        Alternative newAlt{
     1524                                                newExpr, std::move(compositeEnv), std::move(openVars),
     1525                                                AssertionList( need.begin(), need.end() ), first.cost + second.cost };
     1526                                        inferParameters( newAlt, back_inserter( alternatives ) );
    16311527                                } // if
    16321528                        } // for
     
    16461542
    16471543                        TypeEnvironment compositeEnv;
    1648                         simpleCombineEnvironments( alts.begin(), alts.end(), compositeEnv );
    1649                         alternatives.push_back(
    1650                                 Alternative{ new TupleExpr( exprs ), compositeEnv, sumCost( alts ) } );
     1544                        OpenVarSet openVars;
     1545                        AssertionSet need;
     1546                        for ( const Alternative& alt : alts ) {
     1547                                compositeEnv.simpleCombine( alt.env );
     1548                                mergeOpenVars( openVars, alt.openVars );
     1549                                cloneAll( alt.need, need );
     1550                        }
     1551
     1552                        alternatives.push_back( Alternative{
     1553                                new TupleExpr{ exprs }, std::move(compositeEnv), std::move(openVars),
     1554                                AssertionList( need.begin(), need.end() ), sumCost( alts ) } );
    16511555                } // for
    16521556        }
    16531557
    16541558        void AlternativeFinder::Finder::postvisit( TupleExpr *tupleExpr ) {
    1655                 alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
     1559                alternatives.push_back( Alternative{ tupleExpr->clone(), env } );
    16561560        }
    16571561
    16581562        void AlternativeFinder::Finder::postvisit( ImplicitCopyCtorExpr * impCpCtorExpr ) {
    1659                 alternatives.push_back( Alternative( impCpCtorExpr->clone(), env, Cost::zero ) );
     1563                alternatives.push_back( Alternative{ impCpCtorExpr->clone(), env } );
    16601564        }
    16611565
     
    16661570                finder.findWithoutPrune( ctorExpr->get_callExpr() );
    16671571                for ( Alternative & alt : finder.alternatives ) {
    1668                         alternatives.push_back( Alternative( new ConstructorExpr( alt.expr->clone() ), alt.env, alt.cost ) );
     1572                        alternatives.push_back( Alternative{
     1573                                alt, new ConstructorExpr( alt.expr->clone() ), alt.cost } );
    16691574                }
    16701575        }
    16711576
    16721577        void AlternativeFinder::Finder::postvisit( TupleIndexExpr *tupleExpr ) {
    1673                 alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
     1578                alternatives.push_back( Alternative{ tupleExpr->clone(), env } );
    16741579        }
    16751580
    16761581        void AlternativeFinder::Finder::postvisit( TupleAssignExpr *tupleAssignExpr ) {
    1677                 alternatives.push_back( Alternative( tupleAssignExpr->clone(), env, Cost::zero ) );
     1582                alternatives.push_back( Alternative{ tupleAssignExpr->clone(), env } );
    16781583        }
    16791584
     
    16841589                        // ensure that the id is passed on to the UniqueExpr alternative so that the expressions are "linked"
    16851590                        UniqueExpr * newUnqExpr = new UniqueExpr( alt.expr->clone(), unqExpr->get_id() );
    1686                         alternatives.push_back( Alternative( newUnqExpr, alt.env, alt.cost ) );
     1591                        alternatives.push_back( Alternative{ alt, newUnqExpr, alt.cost } );
    16871592                }
    16881593        }
     
    16921597                ResolvExpr::resolveStmtExpr( newStmtExpr, indexer );
    16931598                // xxx - this env is almost certainly wrong, and needs to somehow contain the combined environments from all of the statements in the stmtExpr...
    1694                 alternatives.push_back( Alternative( newStmtExpr, env, Cost::zero ) );
     1599                alternatives.push_back( Alternative{ newStmtExpr, env } );
    16951600        }
    16961601
     
    17141619                        for ( Alternative & alt : finder.get_alternatives() ) {
    17151620                                TypeEnvironment newEnv( alt.env );
    1716                                 AssertionSet needAssertions, haveAssertions;
    1717                                 OpenVarSet openVars;  // find things in env that don't have a "representative type" and claim those are open vars?
     1621                                AssertionSet need;
     1622                                cloneAll( alt.need, need );
     1623                                AssertionSet have;
     1624                                OpenVarSet openVars( alt.openVars );
     1625                                // xxx - find things in env that don't have a "representative type" and claim
     1626                                // those are open vars?
    17181627                                PRINT(
    17191628                                        std::cerr << "  @ " << toType << " " << initAlt.designation << std::endl;
    17201629                                )
    1721                                 // It's possible that a cast can throw away some values in a multiply-valued expression.  (An example is a
    1722                                 // cast-to-void, which casts from one value to zero.)  Figure out the prefix of the subexpression results
    1723                                 // that are cast directly.  The candidate is invalid if it has fewer results than there are types to cast
    1724                                 // to.
     1630                                // It's possible that a cast can throw away some values in a multiply-valued
     1631                                // expression. (An example is a cast-to-void, which casts from one value to
     1632                                // zero.)  Figure out the prefix of the subexpression results that are cast
     1633                                // directly.  The candidate is invalid if it has fewer results than there are
     1634                                // types to cast to.
    17251635                                int discardedValues = alt.expr->result->size() - toType->size();
    17261636                                if ( discardedValues < 0 ) continue;
    1727                                 // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
    1728                                 // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
     1637                                // xxx - may need to go into tuple types and extract relevant types and use
     1638                                // unifyList. Note that currently, this does not allow casting a tuple to an
     1639                                // atomic type (e.g. (int)([1, 2, 3]))
     1640
    17291641                                // unification run for side-effects
    1730                                 unify( toType, alt.expr->result, newEnv, needAssertions, haveAssertions, openVars, indexer ); // xxx - do some inspecting on this line... why isn't result bound to initAlt.type??
    1731 
    1732                                 Cost thisCost = castCost( alt.expr->result, toType, indexer, newEnv );
     1642                                unify( toType, alt.expr->result, newEnv, need, have, openVars, indexer );
     1643                                // xxx - do some inspecting on this line... why isn't result bound to initAlt.type?
     1644
     1645                                Cost thisCost = castCost( alt.expr->result, toType, alt.expr->get_lvalue(),
     1646                                        indexer, newEnv );
    17331647                                if ( thisCost != Cost::infinity ) {
    17341648                                        // count one safe conversion for each value that is thrown away
    17351649                                        thisCost.incSafe( discardedValues );
    1736                                         Alternative newAlt( new InitExpr( restructureCast( alt.expr->clone(), toType, true ), initAlt.designation->clone() ), newEnv, alt.cost, thisCost );
    1737                                         inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( candidates ) );
     1650                                        Alternative newAlt{
     1651                                                new InitExpr{
     1652                                                        restructureCast( alt.expr->clone(), toType, true ), initAlt.designation->clone() },
     1653                                                std::move(newEnv), std::move(openVars),
     1654                                                AssertionList( need.begin(), need.end() ), alt.cost, thisCost };
     1655                                        inferParameters( newAlt, back_inserter( candidates ) );
    17381656                                }
    17391657                        }
  • src/ResolvExpr/AlternativeFinder.h

    r7951100 rb067d9b  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sat May 16 23:56:12 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Jul 26 11:24:00 2017
    13 // Update Count     : 4
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Fri Oct -5 10:01:00 2018
     13// Update Count     : 5
    1414//
    1515
     
    2424#include "ResolvExpr/Cost.h"             // for Cost, Cost::infinity
    2525#include "ResolvExpr/TypeEnvironment.h"  // for AssertionSet, OpenVarSet
     26#include "ResolvMode.h"                  // for ResolvMode
    2627#include "SynTree/Visitor.h"             // for Visitor
    2728#include "SynTree/SynTree.h"             // for Visitor Nodes
     
    3637        /// First index is which argument, second index is which alternative for that argument,
    3738        /// third index is which exploded element of that alternative
    38         using ExplodedArgs = std::vector< std::vector< ExplodedActual > >;
     39        using ExplodedArgs_old = std::vector< std::vector< ExplodedActual > >;
    3940
    4041        class AlternativeFinder {
     
    6869                }
    6970
    70                 void find( Expression *expr, bool adjust = false, bool prune = true, bool failFast = true );
     71                void find( Expression *expr, ResolvMode mode = ResolvMode{} );
    7172                /// Calls find with the adjust flag set; adjustment turns array and function types into equivalent pointer types
    7273                void findWithAdjustment( Expression *expr );
  • src/ResolvExpr/CastCost.cc

    r7951100 rb067d9b  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 06:57:43 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  2 15:34:36 2016
    13 // Update Count     : 7
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu Aug  8 16:12:00 2019
     13// Update Count     : 8
    1414//
    1515
    1616#include <cassert>                       // for assert
    1717
     18#include "AST/Print.hpp"
     19#include "AST/SymbolTable.hpp"
     20#include "AST/Type.hpp"
     21#include "AST/TypeEnvironment.hpp"
    1822#include "ConversionCost.h"              // for ConversionCost
    1923#include "Cost.h"                        // for Cost, Cost::infinity
     
    3135
    3236namespace ResolvExpr {
    33         struct CastCost : public ConversionCost {
     37        struct CastCost_old : public ConversionCost {
    3438          public:
    35                 CastCost( Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc );
     39                CastCost_old( const Type * dest, bool srcIsLvalue,
     40                        const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc );
    3641
    3742                using ConversionCost::previsit;
    3843                using ConversionCost::postvisit;
    39                 void postvisit( BasicType * basicType );
    40                 void postvisit( PointerType * pointerType );
     44                void postvisit( const BasicType * basicType );
     45                void postvisit( const PointerType * pointerType );
    4146        };
    4247
    43         Cost castCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
    44                 if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) {
    45                         if ( const EqvClass* eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {
     48        Cost castCost( const Type * src, const Type * dest, bool srcIsLvalue,
     49                        const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
     50                if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType * >( dest ) ) {
     51                        if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->name ) ) {
    4652                                if ( eqvClass->type ) {
    47                                         return castCost( src, eqvClass->type, indexer, env );
     53                                        return castCost( src, eqvClass->type, srcIsLvalue, indexer, env );
    4854                                } else {
    4955                                        return Cost::infinity;
    5056                                }
    51                         } else if ( NamedTypeDecl *namedType = indexer.lookupType( destAsTypeInst->get_name() ) ) {
     57                        } else if ( const NamedTypeDecl * namedType = indexer.lookupType( destAsTypeInst->name ) ) {
    5258                                // all typedefs should be gone by this point
    53                                 TypeDecl *type = strict_dynamic_cast< TypeDecl* >( namedType );
     59                                const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( namedType );
    5460                                if ( type->base ) {
    55                                         return castCost( src, type->base, indexer, env ) + Cost::safe;
     61                                        return castCost( src, type->base, srcIsLvalue, indexer, env ) + Cost::safe;
    5662                                } // if
    5763                        } // if
     
    7076                        PRINT( std::cerr << "compatible!" << std::endl; )
    7177                        return Cost::zero;
    72                 } else if ( dynamic_cast< VoidType* >( dest ) ) {
     78                } else if ( dynamic_cast< const VoidType * >( dest ) ) {
    7379                        return Cost::safe;
    74                 } else if ( ReferenceType * refType = dynamic_cast< ReferenceType * > ( dest ) ) {
     80                } else if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * > ( dest ) ) {
    7581                        PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )
    76                         return convertToReferenceCost( src, refType, indexer, env, [](Type * t1, Type * t2, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
     82                        return convertToReferenceCost( src, refType, srcIsLvalue, indexer, env, [](const Type * t1, const Type * t2, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
    7783                                return ptrsCastable( t1, t2, env, indexer );
    7884                        });
    7985                } else {
    80                         PassVisitor<CastCost> converter( dest, indexer, env, castCost );
     86                        PassVisitor<CastCost_old> converter(
     87                                dest, srcIsLvalue, indexer, env,
     88                                (Cost (*)( const Type *, const Type *, bool, const SymTab::Indexer &, const TypeEnvironment & ))
     89                                        castCost );
    8190                        src->accept( converter );
    8291                        if ( converter.pass.get_cost() == Cost::infinity ) {
     
    8998        }
    9099
    91         CastCost::CastCost( Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc )
    92                 : ConversionCost( dest, indexer, env, costFunc ) {
    93         }
    94 
    95         void CastCost::postvisit( BasicType *basicType ) {
    96                 PointerType *destAsPointer = dynamic_cast< PointerType* >( dest );
     100        CastCost_old::CastCost_old( const Type * dest, bool srcIsLvalue,
     101                        const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc )
     102                : ConversionCost( dest, srcIsLvalue, indexer, env, costFunc ) {
     103        }
     104
     105        void CastCost_old::postvisit( const BasicType * basicType ) {
     106                const PointerType * destAsPointer = dynamic_cast< const PointerType * >( dest );
    97107                if ( destAsPointer && basicType->isInteger() ) {
    98                         // necessary for, e.g. unsigned long => void*
     108                        // necessary for, e.g. unsigned long => void *
    99109                        cost = Cost::unsafe;
    100110                } else {
    101                         cost = conversionCost( basicType, dest, indexer, env );
     111                        cost = conversionCost( basicType, dest, srcIsLvalue, indexer, env );
    102112                } // if
    103113        }
    104114
    105         void CastCost::postvisit( PointerType *pointerType ) {
    106                 if ( PointerType *destAsPtr = dynamic_cast< PointerType* >( dest ) ) {
    107                         if ( pointerType->get_qualifiers() <= destAsPtr->get_qualifiers() && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) {
     115        void CastCost_old::postvisit( const PointerType * pointerType ) {
     116                if ( const PointerType * destAsPtr = dynamic_cast< const PointerType * >( dest ) ) {
     117                        if ( pointerType->tq <= destAsPtr->tq && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) {
    108118                                cost = Cost::safe;
    109119                        } else {
     
    118128                                } // if
    119129                        } // if
    120                 } else if ( BasicType *destAsBasic = dynamic_cast< BasicType* >( dest ) ) {
     130                } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {
    121131                        if ( destAsBasic->isInteger() ) {
    122                                 // necessary for, e.g. void* => unsigned long
     132                                // necessary for, e.g. void * => unsigned long
    123133                                cost = Cost::unsafe;
    124134                        } // if
    125135                }
    126136        }
     137
     138namespace {
     139        struct CastCost_new : public ConversionCost_new {
     140                using ConversionCost_new::previsit;
     141                using ConversionCost_new::postvisit;
     142
     143                CastCost_new(
     144                        const ast::Type * dst, const ast::SymbolTable & symtab,
     145                        const ast::TypeEnvironment & env, CostCalculation costFunc )
     146                : ConversionCost_new( dst, symtab, env, costFunc ) {}
     147
     148                void postvisit( const ast::BasicType * basicType ) {
     149                        auto ptr = dynamic_cast< const ast::PointerType * >( dst );
     150                        if ( ptr && basicType->isInteger() ) {
     151                                // needed for, e.g. unsigned long => void *
     152                                cost = Cost::unsafe;
     153                        } else {
     154                                cost = conversionCost( basicType, dst, symtab, env );
     155                        }
     156                }
     157
     158                void postvisit( const ast::PointerType * pointerType ) {
     159                        if ( auto ptr = dynamic_cast< const ast::PointerType * >( dst ) ) {
     160                                if (
     161                                        pointerType->qualifiers <= ptr->qualifiers
     162                                        && typesCompatibleIgnoreQualifiers( pointerType->base, ptr->base, symtab, env )
     163                                ) {
     164                                        cost = Cost::safe;
     165                                } else {
     166                                        ast::TypeEnvironment newEnv{ env };
     167                                        if ( auto wParams = pointerType->base.as< ast::ParameterizedType >() ) {
     168                                                newEnv.add( wParams->forall );
     169                                        }
     170                                        int castResult = ptrsCastable( pointerType->base, ptr->base, symtab, newEnv );
     171                                        if ( castResult > 0 ) {
     172                                                cost = Cost::safe;
     173                                        } else if ( castResult < 0 ) {
     174                                                cost = Cost::infinity;
     175                                        }
     176                                }
     177                        } else if ( auto basic = dynamic_cast< const ast::BasicType * >( dst ) ) {
     178                                if ( basic->isInteger() ) {
     179                                        // necessary for, e.g. void * => unsigned long
     180                                        cost = Cost::unsafe;
     181                                }
     182                        }
     183                }
     184        };
     185} // anonymous namespace
     186
     187Cost castCost(
     188        const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
     189        const ast::TypeEnvironment & env
     190) {
     191        if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
     192                if ( const ast::EqvClass * eqvClass = env.lookup( typeInst->name ) ) {
     193                        // check cast cost against bound type, if present
     194                        if ( eqvClass->bound ) {
     195                                return castCost( src, eqvClass->bound, symtab, env );
     196                        } else {
     197                                return Cost::infinity;
     198                        }
     199                } else if ( const ast::NamedTypeDecl * named = symtab.lookupType( typeInst->name ) ) {
     200                        // all typedefs should be gone by now
     201                        auto type = strict_dynamic_cast< const ast::TypeDecl * >( named );
     202                        if ( type->base ) {
     203                                return castCost( src, type->base, symtab, env ) + Cost::safe;
     204                        }
     205                }
     206        }
     207
     208        PRINT(
     209                std::cerr << "castCost ::: src is ";
     210                ast::print( std::cerr, src );
     211                std::cerr << std::endl << "dest is ";
     212                ast::print( std::cerr, dst );
     213                std::cerr << std::endl << "env is" << std::endl;
     214                ast::print( std::cerr, env, 2 );
     215        )
     216
     217        if ( typesCompatibleIgnoreQualifiers( src, dst, symtab, env ) ) {
     218                PRINT( std::cerr << "compatible!" << std::endl; )
     219                return Cost::zero;
     220        } else if ( dynamic_cast< const ast::VoidType * >( dst ) ) {
     221                return Cost::safe;
     222        } else if ( auto refType = dynamic_cast< const ast::ReferenceType * >( dst ) ) {
     223                PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )
     224                #warning cast on ptrsCastable artifact of having two functions, remove when port done
     225                return convertToReferenceCost(
     226                        src, refType, symtab, env,
     227                        ( int (*)(
     228                                const ast::Type *, const ast::Type *, const ast::SymbolTable &,
     229                                const ast::TypeEnvironment & )
     230                        ) ptrsCastable );
     231        } else {
     232                #warning cast on castCost artifact of having two functions, remove when port done
     233                ast::Pass< CastCost_new > converter{
     234                        dst, symtab, env,
     235                        ( Cost (*)(
     236                                const ast::Type *, const ast::Type *, const ast::SymbolTable &,
     237                                const ast::TypeEnvironment & )
     238                        ) castCost };
     239                src->accept( converter );
     240                return converter.pass.cost;
     241        }
     242}
     243
    127244} // namespace ResolvExpr
    128245
  • src/ResolvExpr/CommonType.cc

    r7951100 rb067d9b  
    1010// Created On       : Sun May 17 06:59:27 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Sep 25 15:18:17 2017
    13 // Update Count     : 9
     12// Last Modified On : Thu Feb 14 17:10:10 2019
     13// Update Count     : 24
    1414//
    1515
     
    1818#include <utility>                       // for pair
    1919
     20#include "AST/Decl.hpp"
     21#include "AST/Type.hpp"
    2022#include "Common/PassVisitor.h"
    2123#include "ResolvExpr/TypeEnvironment.h"  // for OpenVarSet, AssertionSet
     
    2426#include "SynTree/Type.h"                // for BasicType, BasicType::Kind::...
    2527#include "SynTree/Visitor.h"             // for Visitor
    26 #include "Unify.h"                       // for unifyExact, bindVar, WidenMode
     28#include "Unify.h"                       // for unifyExact, WidenMode
    2729#include "typeops.h"                     // for isFtype
    2830
     
    3537
    3638namespace ResolvExpr {
    37         struct CommonType : public WithShortCircuiting {
    38                 CommonType( Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars );
    39                 Type *get_result() const { return result; }
     39        struct CommonType_old : public WithShortCircuiting {
     40                CommonType_old( Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars );
     41                Type * get_result() const { return result; }
    4042
    4143                void previsit( BaseSyntaxNode * ) { visit_children = false; }
     
    5860
    5961          private:
    60                 template< typename Pointer > void getCommonWithVoidPointer( Pointer* voidPointer, Pointer* otherPointer );
    61                 template< typename RefType > void handleRefType( RefType *inst, Type *other );
    62 
    63                 Type *result;
    64                 Type *type2;                            // inherited
     62                template< typename Pointer > void getCommonWithVoidPointer( Pointer * voidPointer, Pointer * otherPointer );
     63                template< typename RefType > void handleRefType( RefType * inst, Type * other );
     64
     65                Type * result;
     66                Type * type2;                           // inherited
    6567                bool widenFirst, widenSecond;
    6668                const SymTab::Indexer &indexer;
     
    7880                                std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl;
    7981                        )
    80                         if ( (widenFirst || t2->get_qualifiers() <= t1->get_qualifiers()) && (widenSecond || t1->get_qualifiers() <= t2->get_qualifiers()) ) {
     82                        if ( (widenFirst || t2->tq <= t1->tq) && (widenSecond || t1->tq <= t2->tq) ) {
    8183                                PRINT(
    8284                                        std::cerr << "widen okay" << std::endl;
    8385                                )
    84                                 common->get_qualifiers() |= t1->get_qualifiers();
    85                                 common->get_qualifiers() |= t2->get_qualifiers();
     86                                common->tq |= t1->tq;
     87                                common->tq |= t2->tq;
    8688                                return common;
    8789                        }
     
    9395        }
    9496
    95         Type *commonType( Type *type1, Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ) {
    96                 PassVisitor<CommonType> visitor( type2, widenFirst, widenSecond, indexer, env, openVars );
     97        Type * commonType( Type * type1, Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ) {
     98                PassVisitor<CommonType_old> visitor( type2, widenFirst, widenSecond, indexer, env, openVars );
    9799
    98100                int depth1 = type1->referenceDepth();
     
    125127                                                std::cerr << "formal is reference; result should be reference" << std::endl;
    126128                                        )
    127                                         result = new ReferenceType( ref1->get_qualifiers(), result );
     129                                        result = new ReferenceType( ref1->tq, result );
    128130                                }
    129131                                PRINT(
     
    136138
    137139                type1->accept( visitor );
    138                 Type *result = visitor.pass.get_result();
     140                Type * result = visitor.pass.get_result();
    139141                if ( ! result ) {
    140142                        // this appears to be handling for opaque type declarations
    141143                        if ( widenSecond ) {
    142                                 if ( TypeInstType *inst = dynamic_cast< TypeInstType* >( type2 ) ) {
    143                                         if ( NamedTypeDecl *nt = indexer.lookupType( inst->get_name() ) ) {
    144                                                 TypeDecl *type = strict_dynamic_cast< TypeDecl* >( nt );
     144                                if ( const TypeInstType * inst = dynamic_cast< const TypeInstType * >( type2 ) ) {
     145                                        if ( const NamedTypeDecl * nt = indexer.lookupType( inst->get_name() ) ) {
     146                                                const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( nt );
    145147                                                if ( type->get_base() ) {
    146                                                         Type::Qualifiers tq1 = type1->get_qualifiers(), tq2 = type2->get_qualifiers();
     148                                                        Type::Qualifiers tq1 = type1->tq, tq2 = type2->tq;
    147149                                                        AssertionSet have, need;
    148150                                                        OpenVarSet newOpen( openVars );
    149                                                         type1->get_qualifiers() = Type::Qualifiers();
    150                                                         type->get_base()->get_qualifiers() = tq1;
     151                                                        type1->tq = Type::Qualifiers();
     152                                                        type->get_base()->tq = tq1;
    151153                                                        if ( unifyExact( type1, type->get_base(), env, have, need, newOpen, indexer ) ) {
    152154                                                                result = type1->clone();
    153                                                                 result->get_qualifiers() = tq1 | tq2;
     155                                                                result->tq = tq1 | tq2;
    154156                                                        } // if
    155                                                         type1->get_qualifiers() = tq1;
    156                                                         type->get_base()->get_qualifiers() = Type::Qualifiers();
     157                                                        type1->tq = tq1;
     158                                                        type->get_base()->tq = Type::Qualifiers();
    157159                                                } // if
    158160                                        } // if
     
    176178        }
    177179
    178         static const BasicType::Kind combinedType[][ BasicType::NUMBER_OF_BASIC_TYPES ] =
    179         {
    180 /*              Bool            Char    SignedChar      UnsignedChar    ShortSignedInt  ShortUnsignedInt        SignedInt       UnsignedInt     LongSignedInt   LongUnsignedInt LongLongSignedInt       LongLongUnsignedInt     Float   Double  LongDouble      FloatComplex    DoubleComplex   LongDoubleComplex       FloatImaginary  DoubleImaginary LongDoubleImaginary   SignedInt128   UnsignedInt128   Float80   Float128 */
    181                 /* Bool */      { BasicType::Bool,              BasicType::Char,        BasicType::SignedChar,  BasicType::UnsignedChar,        BasicType::ShortSignedInt,      BasicType::ShortUnsignedInt,    BasicType::SignedInt,   BasicType::UnsignedInt, BasicType::LongSignedInt,       BasicType::LongUnsignedInt,     BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
    182                 /* Char */      { BasicType::Char,              BasicType::Char,        BasicType::UnsignedChar,        BasicType::UnsignedChar,        BasicType::ShortSignedInt,      BasicType::ShortUnsignedInt,    BasicType::SignedInt,   BasicType::UnsignedInt, BasicType::LongSignedInt,       BasicType::LongUnsignedInt,     BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
    183                 /* SignedChar */        { BasicType::SignedChar,        BasicType::UnsignedChar,        BasicType::SignedChar,  BasicType::UnsignedChar,        BasicType::ShortSignedInt,      BasicType::ShortUnsignedInt,    BasicType::SignedInt,   BasicType::UnsignedInt, BasicType::LongSignedInt,       BasicType::LongUnsignedInt,     BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
    184                 /* UnsignedChar */      { BasicType::UnsignedChar,      BasicType::UnsignedChar,        BasicType::UnsignedChar,        BasicType::UnsignedChar,        BasicType::ShortSignedInt,      BasicType::ShortUnsignedInt,    BasicType::SignedInt,   BasicType::UnsignedInt, BasicType::LongSignedInt,       BasicType::LongUnsignedInt,     BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
    185                 /* ShortSignedInt */    { BasicType::ShortSignedInt,    BasicType::ShortSignedInt,      BasicType::ShortSignedInt,      BasicType::ShortSignedInt,      BasicType::ShortSignedInt,      BasicType::ShortUnsignedInt,    BasicType::SignedInt,   BasicType::UnsignedInt, BasicType::LongSignedInt,       BasicType::LongUnsignedInt,     BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
    186                 /* ShortUnsignedInt */  { BasicType::ShortUnsignedInt,  BasicType::ShortUnsignedInt,    BasicType::ShortUnsignedInt,    BasicType::ShortUnsignedInt,    BasicType::ShortUnsignedInt,    BasicType::ShortUnsignedInt,    BasicType::SignedInt,   BasicType::UnsignedInt, BasicType::LongSignedInt,       BasicType::LongUnsignedInt,     BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
    187                 /* SignedInt */         { BasicType::SignedInt,         BasicType::SignedInt,   BasicType::SignedInt,   BasicType::SignedInt,   BasicType::SignedInt,   BasicType::SignedInt,   BasicType::SignedInt,   BasicType::UnsignedInt, BasicType::LongSignedInt,       BasicType::LongUnsignedInt,     BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
    188                 /* UnsignedInt */       { BasicType::UnsignedInt,               BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::UnsignedInt, BasicType::LongUnsignedInt,     BasicType::LongUnsignedInt,     BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
    189                 /* LongSignedInt */     { BasicType::LongSignedInt,             BasicType::LongSignedInt,       BasicType::LongSignedInt,       BasicType::LongSignedInt,       BasicType::LongSignedInt,       BasicType::LongSignedInt,       BasicType::LongSignedInt,       BasicType::LongUnsignedInt,     BasicType::LongSignedInt,       BasicType::LongUnsignedInt,     BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
    190                 /* LongUnsignedInt */   { BasicType::LongUnsignedInt,   BasicType::LongUnsignedInt,     BasicType::LongUnsignedInt,     BasicType::LongUnsignedInt,     BasicType::LongUnsignedInt,     BasicType::LongUnsignedInt,     BasicType::LongUnsignedInt,     BasicType::LongUnsignedInt,     BasicType::LongUnsignedInt,     BasicType::LongUnsignedInt,     BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
    191                 /* LongLongSignedInt */         { BasicType::LongLongSignedInt, BasicType::LongLongSignedInt,   BasicType::LongLongSignedInt,   BasicType::LongLongSignedInt,   BasicType::LongLongSignedInt,   BasicType::LongLongSignedInt,   BasicType::LongLongSignedInt,   BasicType::LongLongSignedInt,   BasicType::LongLongSignedInt,   BasicType::LongLongSignedInt,   BasicType::LongLongSignedInt,   BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
    192                 /* LongLongUnsignedInt */       { BasicType::LongLongUnsignedInt,       BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::LongLongUnsignedInt, BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128 },
    193                 /* Float */     { BasicType::Float,     BasicType::Float,       BasicType::Float,       BasicType::Float,       BasicType::Float,       BasicType::Float,       BasicType::Float,       BasicType::Float,       BasicType::Float,       BasicType::Float,       BasicType::Float,       BasicType::Float,       BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::Float,       BasicType::Float, BasicType::Float80, BasicType::Float128 },
    194                 /* Double */    { BasicType::Double,    BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::Double,      BasicType::LongDouble,  BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::Double,      BasicType::Double, BasicType::Float80, BasicType::Float128 },
    195                 /* LongDouble */        { BasicType::LongDouble,                BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDouble,  BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDouble,  BasicType::LongDouble, BasicType::BasicType::LongDouble, BasicType::Float128 },
    196                 /* FloatComplex */      { BasicType::FloatComplex,      BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::FloatComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, },
    197                 /* DoubleComplex */     { BasicType::DoubleComplex,     BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::DoubleComplex,       BasicType::DoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex },
    198                 /* LongDoubleComplex */         { BasicType::LongDoubleComplex, BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, BasicType::LongDoubleComplex, },
    199                 /* FloatImaginary */    { BasicType::FloatComplex,      BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatImaginary,      BasicType::DoubleImaginary,     BasicType::LongDoubleImaginary, BasicType::FloatImaginary,      BasicType::FloatImaginary, BasicType::LongDoubleImaginary, BasicType::LongDoubleImaginary, },
    200                 /* DoubleImaginary */   { BasicType::DoubleComplex,     BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::DoubleComplex,       BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::DoubleImaginary,     BasicType::DoubleImaginary,     BasicType::LongDoubleImaginary, BasicType::DoubleImaginary,     BasicType::DoubleImaginary, BasicType::LongDoubleImaginary, BasicType::LongDoubleImaginary, },
    201                 /* LongDoubleImaginary */       { BasicType::LongDoubleComplex, BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleImaginary, BasicType::LongDoubleImaginary, BasicType::LongDoubleImaginary, BasicType::LongDoubleImaginary, BasicType::LongDoubleImaginary, },
    202                 /* SignedInt128 */      { BasicType::SignedInt128,      BasicType::SignedInt128,        BasicType::SignedInt128,        BasicType::SignedInt128,        BasicType::SignedInt128,        BasicType::SignedInt128,        BasicType::SignedInt128,        BasicType::SignedInt128,        BasicType::SignedInt128,        BasicType::SignedInt128,        BasicType::SignedInt128,        BasicType::SignedInt128,        BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::SignedInt128,        BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128, },
    203                 /* UnsignedInt128 */    { BasicType::UnsignedInt128,    BasicType::UnsignedInt128,      BasicType::UnsignedInt128,      BasicType::UnsignedInt128,      BasicType::UnsignedInt128,      BasicType::UnsignedInt128,      BasicType::UnsignedInt128,      BasicType::UnsignedInt128,      BasicType::UnsignedInt128,      BasicType::UnsignedInt128,      BasicType::UnsignedInt128,      BasicType::UnsignedInt128,      BasicType::Float,       BasicType::Double,      BasicType::LongDouble,  BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::FloatComplex,        BasicType::DoubleComplex,       BasicType::LongDoubleComplex,   BasicType::UnsignedInt128,      BasicType::UnsignedInt128, BasicType::Float80, BasicType::Float128, },
    204                 /* Float80 */   { BasicType::Float80,   BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::Float80,     BasicType::LongDouble,  BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::Float80,     BasicType::Float80, BasicType::Float80, BasicType::Float128 },
    205                 /* Float128 */  { BasicType::Float128,  BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::Float128,    BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::LongDoubleComplex,   BasicType::Float128,    BasicType::Float128, BasicType::Float128, BasicType::Float128 },
    206         };
     180        // GENERATED START, DO NOT EDIT
     181        // GENERATED BY BasicTypes-gen.cc
     182        #define BT BasicType::
     183        static const BasicType::Kind commonTypes[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // nearest common ancestor
     184                /*                                      B                       C                      SC                      UC                      SI                     SUI
     185                                                        I                      UI                      LI                     LUI                     LLI                    LLUI
     186                                                       IB                     UIB                     _FH                     _FH                      _F                     _FC
     187                                                        F                      FC                     _FX                    _FXC                      FD                    _FDC
     188                                                        D                      DC                    F80X                   _FDXC                     F80                     _FB
     189                                                    _FLDC                      FB                      LD                     LDC                    _FBX                  _FLDXC
     190                                 */
     191                                  {
     192                /*      B */                BT Bool,                BT Char,          BT SignedChar,        BT UnsignedChar,      BT ShortSignedInt,    BT ShortUnsignedInt,
     193                                             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
     194                                          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
     195                                                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
     196                                                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     197                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     198                                  },
     199                                  {
     200                /*      C */                BT Char,                BT Char,          BT SignedChar,        BT UnsignedChar,      BT ShortSignedInt,    BT ShortUnsignedInt,
     201                                             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
     202                                          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
     203                                                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
     204                                                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     205                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     206                                  },
     207                                  {
     208                /*     SC */          BT SignedChar,          BT SignedChar,          BT SignedChar,        BT UnsignedChar,      BT ShortSignedInt,    BT ShortUnsignedInt,
     209                                             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
     210                                          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
     211                                                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
     212                                                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     213                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     214                                  },
     215                                  {
     216                /*     UC */        BT UnsignedChar,        BT UnsignedChar,        BT UnsignedChar,        BT UnsignedChar,      BT ShortSignedInt,    BT ShortUnsignedInt,
     217                                             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
     218                                          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
     219                                                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
     220                                                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     221                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     222                                  },
     223                                  {
     224                /*     SI */      BT ShortSignedInt,      BT ShortSignedInt,      BT ShortSignedInt,      BT ShortSignedInt,      BT ShortSignedInt,    BT ShortUnsignedInt,
     225                                             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
     226                                          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
     227                                                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
     228                                                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     229                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     230                                  },
     231                                  {
     232                /*    SUI */    BT ShortUnsignedInt,    BT ShortUnsignedInt,    BT ShortUnsignedInt,    BT ShortUnsignedInt,    BT ShortUnsignedInt,    BT ShortUnsignedInt,
     233                                             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
     234                                          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
     235                                                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
     236                                                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     237                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     238                                  },
     239                                  {
     240                /*      I */           BT SignedInt,           BT SignedInt,           BT SignedInt,           BT SignedInt,           BT SignedInt,           BT SignedInt,
     241                                             BT SignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
     242                                          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
     243                                                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
     244                                                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     245                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     246                                  },
     247                                  {
     248                /*     UI */         BT UnsignedInt,         BT UnsignedInt,         BT UnsignedInt,         BT UnsignedInt,         BT UnsignedInt,         BT UnsignedInt,
     249                                           BT UnsignedInt,         BT UnsignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
     250                                          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
     251                                                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
     252                                                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     253                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     254                                  },
     255                                  {
     256                /*     LI */       BT LongSignedInt,       BT LongSignedInt,       BT LongSignedInt,       BT LongSignedInt,       BT LongSignedInt,       BT LongSignedInt,
     257                                         BT LongSignedInt,       BT LongSignedInt,       BT LongSignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
     258                                          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
     259                                                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
     260                                                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     261                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     262                                  },
     263                                  {
     264                /*    LUI */     BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,
     265                                       BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,     BT LongUnsignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
     266                                          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
     267                                                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
     268                                                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     269                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     270                                  },
     271                                  {
     272                /*    LLI */   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,
     273                                     BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt,   BT LongLongSignedInt, BT LongLongUnsignedInt,
     274                                          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
     275                                                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
     276                                                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     277                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     278                                  },
     279                                  {
     280                /*   LLUI */ BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt,
     281                                   BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt, BT LongLongUnsignedInt,
     282                                          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
     283                                                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
     284                                                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     285                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     286                                  },
     287                                  {
     288                /*     IB */        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,
     289                                          BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,        BT SignedInt128,
     290                                          BT SignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
     291                                                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
     292                                                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     293                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     294                                  },
     295                                  {
     296                /*    UIB */      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,
     297                                        BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,      BT UnsignedInt128,
     298                                        BT UnsignedInt128,      BT UnsignedInt128,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
     299                                                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
     300                                                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     301                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     302                                  },
     303                                  {
     304                /*    _FH */            BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,
     305                                              BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,            BT uFloat16,
     306                                              BT uFloat16,            BT uFloat16,            BT uFloat16,     BT uFloat16Complex,            BT uFloat32,     BT uFloat32Complex,
     307                                                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
     308                                                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     309                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     310                                  },
     311                                  {
     312                /*    _FH */     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,
     313                                       BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,
     314                                       BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat16Complex,     BT uFloat32Complex,     BT uFloat32Complex,
     315                                          BT FloatComplex,        BT FloatComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,     BT uFloat64Complex,     BT uFloat64Complex,
     316                                         BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
     317                                      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
     318                                  },
     319                                  {
     320                /*     _F */            BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,
     321                                              BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,            BT uFloat32,
     322                                              BT uFloat32,            BT uFloat32,            BT uFloat32,     BT uFloat32Complex,            BT uFloat32,     BT uFloat32Complex,
     323                                                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
     324                                                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     325                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     326                                  },
     327                                  {
     328                /*    _FC */     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,
     329                                       BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,
     330                                       BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,     BT uFloat32Complex,
     331                                          BT FloatComplex,        BT FloatComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,     BT uFloat64Complex,     BT uFloat64Complex,
     332                                         BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
     333                                      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
     334                                  },
     335                                  {
     336                /*      F */               BT Float,               BT Float,               BT Float,               BT Float,               BT Float,               BT Float,
     337                                                 BT Float,               BT Float,               BT Float,               BT Float,               BT Float,               BT Float,
     338                                                 BT Float,               BT Float,               BT Float,        BT FloatComplex,               BT Float,        BT FloatComplex,
     339                                                 BT Float,        BT FloatComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
     340                                                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     341                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     342                                  },
     343                                  {
     344                /*     FC */        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,
     345                                          BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,
     346                                          BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,        BT FloatComplex,
     347                                          BT FloatComplex,        BT FloatComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,     BT uFloat64Complex,     BT uFloat64Complex,
     348                                         BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
     349                                      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
     350                                  },
     351                                  {
     352                /*    _FX */           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,
     353                                             BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,           BT uFloat32x,
     354                                             BT uFloat32x,           BT uFloat32x,           BT uFloat32x,    BT uFloat32xComplex,           BT uFloat32x,    BT uFloat32xComplex,
     355                                             BT uFloat32x,    BT uFloat32xComplex,           BT uFloat32x,    BT uFloat32xComplex,            BT uFloat64,     BT uFloat64Complex,
     356                                                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     357                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     358                                  },
     359                                  {
     360                /*   _FXC */    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,
     361                                      BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,
     362                                      BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,
     363                                      BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,    BT uFloat32xComplex,     BT uFloat64Complex,     BT uFloat64Complex,
     364                                         BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
     365                                      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
     366                                  },
     367                                  {
     368                /*     FD */            BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,
     369                                              BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,            BT uFloat64,
     370                                              BT uFloat64,            BT uFloat64,            BT uFloat64,     BT uFloat64Complex,            BT uFloat64,     BT uFloat64Complex,
     371                                              BT uFloat64,     BT uFloat64Complex,            BT uFloat64,     BT uFloat64Complex,            BT uFloat64,     BT uFloat64Complex,
     372                                                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     373                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     374                                  },
     375                                  {
     376                /*   _FDC */     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,
     377                                       BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,
     378                                       BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,
     379                                       BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,     BT uFloat64Complex,
     380                                         BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
     381                                      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
     382                                  },
     383                                  {
     384                /*      D */              BT Double,              BT Double,              BT Double,              BT Double,              BT Double,              BT Double,
     385                                                BT Double,              BT Double,              BT Double,              BT Double,              BT Double,              BT Double,
     386                                                BT Double,              BT Double,              BT Double,       BT DoubleComplex,              BT Double,       BT DoubleComplex,
     387                                                BT Double,       BT DoubleComplex,              BT Double,       BT DoubleComplex,              BT Double,       BT DoubleComplex,
     388                                                BT Double,       BT DoubleComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     389                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     390                                  },
     391                                  {
     392                /*     DC */       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,
     393                                         BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,
     394                                         BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,
     395                                         BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,       BT DoubleComplex,
     396                                         BT DoubleComplex,       BT DoubleComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
     397                                      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
     398                                  },
     399                                  {
     400                /*   F80X */           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,
     401                                             BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,           BT uFloat64x,
     402                                             BT uFloat64x,           BT uFloat64x,           BT uFloat64x,    BT uFloat64xComplex,           BT uFloat64x,    BT uFloat64xComplex,
     403                                             BT uFloat64x,    BT uFloat64xComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uFloat64x,    BT uFloat64xComplex,
     404                                             BT uFloat64x,    BT uFloat64xComplex,           BT uFloat64x,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     405                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     406                                  },
     407                                  {
     408                /*  _FDXC */    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,
     409                                      BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,
     410                                      BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,
     411                                      BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,
     412                                      BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat64xComplex,    BT uFloat128Complex,
     413                                      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
     414                                  },
     415                                  {
     416                /*    F80 */           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,
     417                                             BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,           BT uuFloat80,
     418                                             BT uuFloat80,           BT uuFloat80,           BT uuFloat80,    BT uFloat64xComplex,           BT uuFloat80,    BT uFloat64xComplex,
     419                                             BT uuFloat80,    BT uFloat64xComplex,           BT uuFloat80,    BT uFloat64xComplex,           BT uuFloat80,    BT uFloat64xComplex,
     420                                             BT uuFloat80,    BT uFloat64xComplex,           BT uuFloat80,    BT uFloat64xComplex,           BT uuFloat80,           BT uFloat128,
     421                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     422                                  },
     423                                  {
     424                /*    _FB */           BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,
     425                                             BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,           BT uFloat128,
     426                                             BT uFloat128,           BT uFloat128,           BT uFloat128,    BT uFloat128Complex,           BT uFloat128,    BT uFloat128Complex,
     427                                             BT uFloat128,    BT uFloat128Complex,           BT uFloat128,    BT uFloat128Complex,           BT uFloat128,    BT uFloat128Complex,
     428                                             BT uFloat128,    BT uFloat128Complex,           BT uFloat128,    BT uFloat128Complex,           BT uFloat128,           BT uFloat128,
     429                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     430                                  },
     431                                  {
     432                /*  _FLDC */    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,
     433                                      BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,
     434                                      BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,
     435                                      BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,
     436                                      BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,    BT uFloat128Complex,
     437                                      BT uFloat128Complex,    BT uFloat128Complex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
     438                                  },
     439                                  {
     440                /*     FB */          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,
     441                                            BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,          BT uuFloat128,
     442                                            BT uuFloat128,          BT uuFloat128,          BT uuFloat128,    BT uFloat128Complex,          BT uuFloat128,    BT uFloat128Complex,
     443                                            BT uuFloat128,    BT uFloat128Complex,          BT uuFloat128,    BT uFloat128Complex,          BT uuFloat128,    BT uFloat128Complex,
     444                                            BT uuFloat128,    BT uFloat128Complex,          BT uuFloat128,    BT uFloat128Complex,          BT uuFloat128,          BT uuFloat128,
     445                                      BT uFloat128Complex,          BT uuFloat128,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     446                                  },
     447                                  {
     448                /*     LD */          BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,
     449                                            BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,          BT LongDouble,
     450                                            BT LongDouble,          BT LongDouble,          BT LongDouble,   BT LongDoubleComplex,          BT LongDouble,   BT LongDoubleComplex,
     451                                            BT LongDouble,   BT LongDoubleComplex,          BT LongDouble,   BT LongDoubleComplex,          BT LongDouble,   BT LongDoubleComplex,
     452                                            BT LongDouble,   BT LongDoubleComplex,          BT LongDouble,   BT LongDoubleComplex,          BT LongDouble,          BT LongDouble,
     453                                     BT LongDoubleComplex,          BT LongDouble,          BT LongDouble,   BT LongDoubleComplex,          BT uFloat128x,   BT uFloat128xComplex,
     454                                  },
     455                                  {
     456                /*    LDC */   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,
     457                                     BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,
     458                                     BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,
     459                                     BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,
     460                                     BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,
     461                                     BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT LongDoubleComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
     462                                  },
     463                                  {
     464                /*   _FBX */          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,
     465                                            BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,          BT uFloat128x,
     466                                            BT uFloat128x,          BT uFloat128x,          BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,   BT uFloat128xComplex,
     467                                            BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,   BT uFloat128xComplex,
     468                                            BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,          BT uFloat128x,
     469                                     BT uFloat128xComplex,          BT uFloat128x,          BT uFloat128x,   BT uFloat128xComplex,          BT uFloat128x,   BT uFloat128xComplex,
     470                                  },
     471                                  {
     472                /* _FLDXC */   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
     473                                     BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
     474                                     BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
     475                                     BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
     476                                     BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
     477                                     BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,   BT uFloat128xComplex,
     478                                  },
     479        }; // commonTypes
     480        #undef BT
     481        // GENERATED END
    207482        static_assert(
    208                 sizeof(combinedType)/sizeof(combinedType[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES,
     483                sizeof(commonTypes)/sizeof(commonTypes[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES * BasicType::NUMBER_OF_BASIC_TYPES,
    209484                "Each basic type kind should have a corresponding row in the combined type matrix"
    210485        );
    211486
    212         CommonType::CommonType( Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars )
     487        CommonType_old::CommonType_old( Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars )
    213488                : result( 0 ), type2( type2 ), widenFirst( widenFirst ), widenSecond( widenSecond ), indexer( indexer ), env( env ), openVars( openVars ) {
    214489        }
    215490
    216         void CommonType::postvisit( VoidType * ) {}
    217 
    218         void CommonType::postvisit( BasicType *basicType ) {
    219                 if ( BasicType *otherBasic = dynamic_cast< BasicType* >( type2 ) ) {
    220                         BasicType::Kind newType = combinedType[ basicType->get_kind() ][ otherBasic->get_kind() ];
    221                         if ( ( ( newType == basicType->get_kind() && basicType->get_qualifiers() >= otherBasic->get_qualifiers() ) || widenFirst ) && ( ( newType == otherBasic->get_kind() && basicType->get_qualifiers() <= otherBasic->get_qualifiers() ) || widenSecond ) ) {
    222                                 result = new BasicType( basicType->get_qualifiers() | otherBasic->get_qualifiers(), newType );
     491        void CommonType_old::postvisit( VoidType * ) {}
     492
     493        void CommonType_old::postvisit( BasicType * basicType ) {
     494                if ( BasicType * otherBasic = dynamic_cast< BasicType * >( type2 ) ) {
     495                        BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ otherBasic->get_kind() ];
     496                        if ( ( ( newType == basicType->get_kind() && basicType->tq >= otherBasic->tq ) || widenFirst ) && ( ( newType == otherBasic->get_kind() && basicType->tq <= otherBasic->tq ) || widenSecond ) ) {
     497                                result = new BasicType( basicType->tq | otherBasic->tq, newType );
    223498                        } // if
    224                 } else if ( dynamic_cast< EnumInstType * > ( type2 ) || dynamic_cast< ZeroType* >( type2 ) || dynamic_cast< OneType* >( type2 ) ) {
     499                } else if ( dynamic_cast< EnumInstType * > ( type2 ) || dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) {
    225500                        // use signed int in lieu of the enum/zero/one type
    226                         BasicType::Kind newType = combinedType[ basicType->get_kind() ][ BasicType::SignedInt ];
    227                         if ( ( ( newType == basicType->get_kind() && basicType->get_qualifiers() >= type2->get_qualifiers() ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->get_qualifiers() <= type2->get_qualifiers() ) || widenSecond ) ) {
    228                                 result = new BasicType( basicType->get_qualifiers() | type2->get_qualifiers(), newType );
     501                        BasicType::Kind newType = commonTypes[ basicType->get_kind() ][ BasicType::SignedInt ];
     502                        if ( ( ( newType == basicType->get_kind() && basicType->tq >= type2->tq ) || widenFirst ) && ( ( newType != basicType->get_kind() && basicType->tq <= type2->tq ) || widenSecond ) ) {
     503                                result = new BasicType( basicType->tq | type2->tq, newType );
    229504                        } // if
    230505                } // if
     
    232507
    233508        template< typename Pointer >
    234         void CommonType::getCommonWithVoidPointer( Pointer* voidPointer, Pointer* otherPointer ) {
    235                 if ( TypeInstType* var = dynamic_cast< TypeInstType* >( otherPointer->get_base() ) ) {
     509        void CommonType_old::getCommonWithVoidPointer( Pointer * voidPointer, Pointer * otherPointer ) {
     510                if ( TypeInstType * var = dynamic_cast< TypeInstType * >( otherPointer->get_base() ) ) {
    236511                        OpenVarSet::const_iterator entry = openVars.find( var->get_name() );
    237512                        if ( entry != openVars.end() ) {
    238513                                AssertionSet need, have;
    239514                                WidenMode widen( widenFirst, widenSecond );
    240                                 if ( entry != openVars.end() && ! bindVar(var, voidPointer->get_base(), entry->second, env, need, have, openVars, widen, indexer ) ) return;
     515                                if ( entry != openVars.end() && ! env.bindVar(var, voidPointer->get_base(), entry->second, need, have, openVars, widen, indexer ) ) return;
    241516                        }
    242517                }
    243518                result = voidPointer->clone();
    244                 result->get_qualifiers() |= otherPointer->get_qualifiers();
    245         }
    246 
    247         void CommonType::postvisit( PointerType *pointerType ) {
    248                 if ( PointerType *otherPointer = dynamic_cast< PointerType* >( type2 ) ) {
     519                result->tq |= otherPointer->tq;
     520        }
     521
     522        void CommonType_old::postvisit( PointerType * pointerType ) {
     523                if ( PointerType * otherPointer = dynamic_cast< PointerType * >( type2 ) ) {
    249524                        // std::cerr << "commonType: two pointers: " << pointerType << " / " << otherPointer << std::endl;
    250                         if ( widenFirst && dynamic_cast< VoidType* >( otherPointer->get_base() ) && ! isFtype(pointerType->get_base()) ) {
     525                        if ( widenFirst && dynamic_cast< VoidType * >( otherPointer->get_base() ) && ! isFtype(pointerType->get_base()) ) {
    251526                                getCommonWithVoidPointer( otherPointer, pointerType );
    252                         } else if ( widenSecond && dynamic_cast< VoidType* >( pointerType->get_base() ) && ! isFtype(otherPointer->get_base()) ) {
     527                        } else if ( widenSecond && dynamic_cast< VoidType * >( pointerType->get_base() ) && ! isFtype(otherPointer->get_base()) ) {
    253528                                getCommonWithVoidPointer( pointerType, otherPointer );
    254                         } else if ( ( pointerType->get_base()->get_qualifiers() >= otherPointer->get_base()->get_qualifiers() || widenFirst )
    255                                            && ( pointerType->get_base()->get_qualifiers() <= otherPointer->get_base()->get_qualifiers() || widenSecond ) ) {
     529                        } else if ( ( pointerType->get_base()->tq >= otherPointer->get_base()->tq || widenFirst )
     530                                           && ( pointerType->get_base()->tq <= otherPointer->get_base()->tq || widenSecond ) ) {
    256531                                // std::cerr << "middle case" << std::endl;
    257                                 Type::Qualifiers tq1 = pointerType->get_base()->get_qualifiers(), tq2 = otherPointer->get_base()->get_qualifiers();
    258                                 pointerType->get_base()->get_qualifiers() = Type::Qualifiers();
    259                                 otherPointer->get_base()->get_qualifiers() = Type::Qualifiers();
     532                                Type::Qualifiers tq1 = pointerType->get_base()->tq, tq2 = otherPointer->get_base()->tq;
     533                                pointerType->get_base()->tq = Type::Qualifiers();
     534                                otherPointer->get_base()->tq = Type::Qualifiers();
    260535                                AssertionSet have, need;
    261536                                OpenVarSet newOpen( openVars );
     
    267542                                                result = otherPointer->clone();
    268543                                        } // if
    269                                         result->get_qualifiers() = tq1 | tq2;
     544                                        strict_dynamic_cast<PointerType *>(result)->base->tq = tq1 | tq2;
    270545                                } else {
    271546                                        /// std::cerr << "place for ptr-to-type" << std::endl;
    272547                                } // if
    273                                 pointerType->get_base()->get_qualifiers() = tq1;
    274                                 otherPointer->get_base()->get_qualifiers() = tq2;
     548                                pointerType->get_base()->tq = tq1;
     549                                otherPointer->get_base()->tq = tq2;
    275550                        } // if
    276                 } else if ( widenSecond && dynamic_cast< ZeroType* >( type2 ) ) {
     551                } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {
    277552                        result = pointerType->clone();
    278                         result->get_qualifiers() |= type2->get_qualifiers();
     553                        result->tq |= type2->tq;
    279554                } // if
    280555        }
    281556
    282         void CommonType::postvisit( ArrayType * ) {}
    283 
    284         void CommonType::postvisit( ReferenceType *refType ) {
    285                 if ( ReferenceType *otherRef = dynamic_cast< ReferenceType* >( type2 ) ) {
     557        void CommonType_old::postvisit( ArrayType * ) {}
     558
     559        void CommonType_old::postvisit( ReferenceType * refType ) {
     560                if ( ReferenceType * otherRef = dynamic_cast< ReferenceType * >( type2 ) ) {
    286561                        // std::cerr << "commonType: both references: " << refType << " / " << otherRef << std::endl;
    287                         // std::cerr << ( refType->get_base()->get_qualifiers() >= otherRef->get_base()->get_qualifiers() || widenFirst ) << (refType->get_base()->get_qualifiers() <= otherRef->get_base()->get_qualifiers() || widenSecond) << std::endl;
    288                         if ( widenFirst && dynamic_cast< VoidType* >( otherRef->get_base() ) && ! isFtype(refType->get_base()) ) {
     562                        // std::cerr << ( refType->get_base()->tq >= otherRef->get_base()->tq || widenFirst ) << (refType->get_base()->tq <= otherRef->get_base()->tq || widenSecond) << std::endl;
     563                        if ( widenFirst && dynamic_cast< VoidType * >( otherRef->get_base() ) && ! isFtype(refType->get_base()) ) {
    289564                                getCommonWithVoidPointer( otherRef, refType );
    290                         } else if ( widenSecond && dynamic_cast< VoidType* >( refType->get_base() ) && ! isFtype(otherRef->get_base()) ) {
     565                        } else if ( widenSecond && dynamic_cast< VoidType * >( refType->get_base() ) && ! isFtype(otherRef->get_base()) ) {
    291566                                getCommonWithVoidPointer( refType, otherRef );
    292                         } else if ( ( refType->get_base()->get_qualifiers() >= otherRef->get_base()->get_qualifiers() || widenFirst )
    293                                            && ( refType->get_base()->get_qualifiers() <= otherRef->get_base()->get_qualifiers() || widenSecond ) ) {
     567                        } else if ( ( refType->get_base()->tq >= otherRef->get_base()->tq || widenFirst )
     568                                           && ( refType->get_base()->tq <= otherRef->get_base()->tq || widenSecond ) ) {
    294569                                // std::cerr << "middle case" << std::endl;
    295                                 Type::Qualifiers tq1 = refType->get_base()->get_qualifiers(), tq2 = otherRef->get_base()->get_qualifiers();
    296                                 refType->get_base()->get_qualifiers() = Type::Qualifiers();
    297                                 otherRef->get_base()->get_qualifiers() = Type::Qualifiers();
     570                                Type::Qualifiers tq1 = refType->get_base()->tq, tq2 = otherRef->get_base()->tq;
     571                                refType->get_base()->tq = Type::Qualifiers();
     572                                otherRef->get_base()->tq = Type::Qualifiers();
    298573                                AssertionSet have, need;
    299574                                OpenVarSet newOpen( openVars );
     
    304579                                                result = otherRef->clone();
    305580                                        } // if
    306                                         result->get_qualifiers() = tq1 | tq2;
     581                                        strict_dynamic_cast<ReferenceType *>(result)->base->tq = tq1 | tq2;
    307582                                } else {
    308583                                        /// std::cerr << "place for ptr-to-type" << std::endl;
    309584                                } // if
    310                                 refType->get_base()->get_qualifiers() = tq1;
    311                                 otherRef->get_base()->get_qualifiers() = tq2;
     585                                refType->get_base()->tq = tq1;
     586                                otherRef->get_base()->tq = tq2;
    312587                        } // if
    313                 } else if ( widenSecond && dynamic_cast< ZeroType* >( type2 ) ) {
     588                } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {
    314589                        result = refType->clone();
    315                         result->get_qualifiers() |= type2->get_qualifiers();
     590                        result->tq |= type2->tq;
    316591                } // if
    317592        }
    318593
    319         void CommonType::postvisit( FunctionType * ) {}
    320         void CommonType::postvisit( StructInstType * ) {}
    321         void CommonType::postvisit( UnionInstType * ) {}
    322 
    323         void CommonType::postvisit( EnumInstType *enumInstType ) {
    324                 if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< ZeroType* >( type2 ) || dynamic_cast< OneType* >( type2 ) ) {
     594        void CommonType_old::postvisit( FunctionType * ) {}
     595        void CommonType_old::postvisit( StructInstType * ) {}
     596        void CommonType_old::postvisit( UnionInstType * ) {}
     597
     598        void CommonType_old::postvisit( EnumInstType * enumInstType ) {
     599                if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< ZeroType * >( type2 ) || dynamic_cast< OneType * >( type2 ) ) {
    325600                        // reuse BasicType, EnumInstType code by swapping type2 with enumInstType
    326601                        result = commonType( type2, enumInstType, widenSecond, widenFirst, indexer, env, openVars );
     
    328603        }
    329604
    330         void CommonType::postvisit( TraitInstType * ) {
    331         }
    332 
    333         void CommonType::postvisit( TypeInstType *inst ) {
     605        void CommonType_old::postvisit( TraitInstType * ) {
     606        }
     607
     608        void CommonType_old::postvisit( TypeInstType * inst ) {
    334609                if ( widenFirst ) {
    335                         NamedTypeDecl *nt = indexer.lookupType( inst->get_name() );
     610                        const NamedTypeDecl * nt = indexer.lookupType( inst->get_name() );
    336611                        if ( nt ) {
    337                                 TypeDecl *type = strict_dynamic_cast< TypeDecl* >( nt );
     612                                const TypeDecl * type = strict_dynamic_cast< const TypeDecl * >( nt );
    338613                                if ( type->get_base() ) {
    339                                         Type::Qualifiers tq1 = inst->get_qualifiers(), tq2 = type2->get_qualifiers();
     614                                        Type::Qualifiers tq1 = inst->tq, tq2 = type2->tq;
    340615                                        AssertionSet have, need;
    341616                                        OpenVarSet newOpen( openVars );
    342                                         type2->get_qualifiers() = Type::Qualifiers();
    343                                         type->get_base()->get_qualifiers() = tq1;
     617                                        type2->tq = Type::Qualifiers();
     618                                        type->get_base()->tq = tq1;
    344619                                        if ( unifyExact( type->get_base(), type2, env, have, need, newOpen, indexer ) ) {
    345620                                                result = type2->clone();
    346                                                 result->get_qualifiers() = tq1 | tq2;
     621                                                result->tq = tq1 | tq2;
    347622                                        } // if
    348                                         type2->get_qualifiers() = tq2;
    349                                         type->get_base()->get_qualifiers() = Type::Qualifiers();
     623                                        type2->tq = tq2;
     624                                        type->get_base()->tq = Type::Qualifiers();
    350625                                } // if
    351626                        } // if
     
    353628        }
    354629
    355         void CommonType::postvisit( TupleType * ) {}
    356         void CommonType::postvisit( VarArgsType * ) {}
    357 
    358         void CommonType::postvisit( ZeroType *zeroType ) {
     630        void CommonType_old::postvisit( TupleType * ) {}
     631        void CommonType_old::postvisit( VarArgsType * ) {}
     632
     633        void CommonType_old::postvisit( ZeroType * zeroType ) {
    359634                if ( widenFirst ) {
    360                         if ( dynamic_cast< BasicType* >( type2 ) || dynamic_cast< PointerType* >( type2 ) || dynamic_cast< EnumInstType* >( type2 ) ) {
    361                                 if ( widenSecond || zeroType->get_qualifiers() <= type2->get_qualifiers() ) {
     635                        if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< PointerType * >( type2 ) || dynamic_cast< EnumInstType * >( type2 ) ) {
     636                                if ( widenSecond || zeroType->tq <= type2->tq ) {
    362637                                        result = type2->clone();
    363                                         result->get_qualifiers() |= zeroType->get_qualifiers();
    364                                 }
    365                         } else if ( widenSecond && dynamic_cast< OneType* >( type2 ) ) {
    366                                 result = new BasicType( zeroType->get_qualifiers(), BasicType::SignedInt );
    367                                 result->get_qualifiers() |= type2->get_qualifiers();
    368                         }
    369                 }
    370         }
    371 
    372         void CommonType::postvisit( OneType *oneType ) {
     638                                        result->tq |= zeroType->tq;
     639                                }
     640                        } else if ( widenSecond && dynamic_cast< OneType * >( type2 ) ) {
     641                                result = new BasicType( zeroType->tq, BasicType::SignedInt );
     642                                result->tq |= type2->tq;
     643                        }
     644                }
     645        }
     646
     647        void CommonType_old::postvisit( OneType * oneType ) {
    373648                if ( widenFirst ) {
    374                         if ( dynamic_cast< BasicType* >( type2 ) || dynamic_cast< EnumInstType* >( type2 ) ) {
    375                                 if ( widenSecond || oneType->get_qualifiers() <= type2->get_qualifiers() ) {
     649                        if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< EnumInstType * >( type2 ) ) {
     650                                if ( widenSecond || oneType->tq <= type2->tq ) {
    376651                                        result = type2->clone();
    377                                         result->get_qualifiers() |= oneType->get_qualifiers();
    378                                 }
    379                         } else if ( widenSecond && dynamic_cast< ZeroType* >( type2 ) ) {
    380                                 result = new BasicType( oneType->get_qualifiers(), BasicType::SignedInt );
    381                                 result->get_qualifiers() |= type2->get_qualifiers();
    382                         }
    383                 }
    384         }
     652                                        result->tq |= oneType->tq;
     653                                }
     654                        } else if ( widenSecond && dynamic_cast< ZeroType * >( type2 ) ) {
     655                                result = new BasicType( oneType->tq, BasicType::SignedInt );
     656                                result->tq |= type2->tq;
     657                        }
     658                }
     659        }
     660
     661        class CommonType_new final : public ast::WithShortCircuiting {
     662                const ast::Type * type2;
     663                WidenMode widen;
     664                const ast::SymbolTable & symtab;
     665                ast::TypeEnvironment & tenv;
     666                const ast::OpenVarSet & open;
     667        public:
     668                ast::ptr< ast::Type > result;
     669
     670                CommonType_new(
     671                        const ast::Type * t2, WidenMode w, const ast::SymbolTable & st,
     672                        ast::TypeEnvironment & env, const ast::OpenVarSet & o )
     673                : type2( t2 ), widen( w ), symtab( st ), tenv( env ), open( o ), result() {}
     674
     675                void previsit( const ast::Node * ) { visit_children = false; }
     676
     677                void postvisit( const ast::VoidType * ) {}
     678
     679                void postvisit( const ast::BasicType * basic ) {
     680                        if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) {
     681                                #warning remove casts when `commonTypes` moved to new AST
     682                                ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)basic2->kind ];
     683                                if (
     684                                        ( ( kind == basic->kind && basic->qualifiers >= basic2->qualifiers )
     685                                                || widen.first )
     686                                        && ( ( kind == basic2->kind && basic->qualifiers <= basic2->qualifiers )
     687                                                || widen.second )
     688                                ) {
     689                                        result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers };
     690                                }
     691                        } else if (
     692                                dynamic_cast< const ast::EnumInstType * >( type2 )
     693                                || dynamic_cast< const ast::ZeroType * >( type2 )
     694                                || dynamic_cast< const ast::OneType * >( type2 )
     695                        ) {
     696                                #warning remove casts when `commonTypes` moved to new AST
     697                                ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)ast::BasicType::SignedInt ];
     698                                if (
     699                                        ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers )
     700                                                || widen.first )
     701                                        && ( ( kind != basic->kind && basic->qualifiers <= type2->qualifiers )
     702                                                || widen.second )
     703                                ) {
     704                                        result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers };
     705                                }
     706                        }
     707                }
     708
     709        private:
     710                template< typename Pointer >
     711                void getCommonWithVoidPointer( const Pointer * voidPtr, const Pointer * oPtr ) {
     712                        const ast::Type * base = oPtr->base;
     713                        if ( auto var = dynamic_cast< const ast::TypeInstType * >( base ) ) {
     714                                auto entry = open.find( var->name );
     715                                if ( entry != open.end() ) {
     716                                        ast::AssertionSet need, have;
     717                                        if ( ! tenv.bindVar(
     718                                                var, voidPtr->base, entry->second, need, have, open, widen, symtab )
     719                                        ) return;
     720                                }
     721                        }
     722                        result = voidPtr;
     723                        add_qualifiers( result, oPtr->qualifiers );
     724                }
     725
     726        public:
     727                void postvisit( const ast::PointerType * pointer ) {
     728                        if ( auto pointer2 = dynamic_cast< const ast::PointerType * >( type2 ) ) {
     729                                if (
     730                                        widen.first
     731                                        && pointer2->base.as< ast::VoidType >()
     732                                        && ! ast::isFtype( pointer->base )
     733                                ) {
     734                                        getCommonWithVoidPointer( pointer2, pointer );
     735                                } else if (
     736                                        widen.second
     737                                        && pointer->base.as< ast::VoidType >()
     738                                        && ! ast::isFtype( pointer2->base )
     739                                ) {
     740                                        getCommonWithVoidPointer( pointer, pointer2 );
     741                                } else if (
     742                                        ( pointer->base->qualifiers >= pointer2->base->qualifiers || widen.first )
     743                                        && ( pointer->base->qualifiers <= pointer2->base->qualifiers || widen.second )
     744                                ) {
     745                                        ast::CV::Qualifiers q1 = pointer->base->qualifiers;
     746                                        ast::CV::Qualifiers q2 = pointer2->base->qualifiers;
     747
     748                                        // force t{1,2} to be cloned if their qualifiers must be stripped, so that
     749                                        // pointer{,2}->base are unchanged
     750                                        ast::ptr< ast::Type > t1{ pointer->base }, t2{ pointer2->base };
     751                                        reset_qualifiers( t1 );
     752                                        reset_qualifiers( t2 );
     753
     754                                        ast::AssertionSet have, need;
     755                                        ast::OpenVarSet newOpen{ open };
     756                                        if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden(), symtab ) ) {
     757                                                result = pointer;
     758                                                if ( q1.val != q2.val ) {
     759                                                        // reset result->base->qualifiers to be union of two base qualifiers
     760                                                        strict_dynamic_cast< ast::PointerType * >(
     761                                                                result.get_and_mutate()
     762                                                        )->base.get_and_mutate()->qualifiers = q1 | q2;
     763                                                }
     764                                        }
     765                                }
     766                        } else if ( widen.second && dynamic_cast< const ast::ZeroType * >( type2 ) ) {
     767                                result = pointer;
     768                                add_qualifiers( result, type2->qualifiers );
     769                        }
     770                }
     771
     772                void postvisit( const ast::ArrayType * ) {}
     773
     774                void postvisit( const ast::ReferenceType * ref ) {
     775                        if ( auto ref2 = dynamic_cast< const ast::ReferenceType * >( type2 ) ) {
     776                                if (
     777                                        widen.first && ref2->base.as< ast::VoidType >() && ! ast::isFtype( ref->base )
     778                                ) {
     779                                        getCommonWithVoidPointer( ref2, ref );
     780                                } else if (
     781                                        widen.second && ref->base.as< ast::VoidType>() && ! ast::isFtype( ref2->base )
     782                                ) {
     783                                        getCommonWithVoidPointer( ref, ref2 );
     784                                } else if (
     785                                        ( ref->base->qualifiers >= ref2->base->qualifiers || widen.first )
     786                                        && ( ref->base->qualifiers <= ref2->base->qualifiers || widen.second )
     787                                ) {
     788                                        ast::CV::Qualifiers q1 = ref->base->qualifiers, q2 = ref2->base->qualifiers;
     789
     790                                        // force t{1,2} to be cloned if their qualifiers must be stripped, so that
     791                                        // ref{,2}->base are unchanged
     792                                        ast::ptr< ast::Type > t1{ ref->base }, t2{ ref2->base };
     793                                        reset_qualifiers( t1 );
     794                                        reset_qualifiers( t2 );
     795
     796                                        ast::AssertionSet have, need;
     797                                        ast::OpenVarSet newOpen{ open };
     798                                        if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden(), symtab ) ) {
     799                                                result = ref;
     800                                                if ( q1.val != q2.val ) {
     801                                                        // reset result->base->qualifiers to be union of two base qualifiers
     802                                                        strict_dynamic_cast< ast::ReferenceType * >(
     803                                                                result.get_and_mutate()
     804                                                        )->base.get_and_mutate()->qualifiers = q1 | q2;
     805                                                }
     806                                        }
     807                                }
     808                        } else if ( widen.second && dynamic_cast< const ast::ZeroType * >( type2 ) ) {
     809                                result = ref;
     810                                add_qualifiers( result, type2->qualifiers );
     811                        }
     812                }
     813
     814                void postvisit( const ast::FunctionType * ) {}
     815
     816                void postvisit( const ast::StructInstType * ) {}
     817
     818                void postvisit( const ast::UnionInstType * ) {}
     819
     820                void postvisit( const ast::EnumInstType * enumInst ) {
     821                        if (
     822                                dynamic_cast< const ast::BasicType * >( type2 )
     823                                || dynamic_cast< const ast::ZeroType * >( type2 )
     824                                || dynamic_cast< const ast::OneType * >( type2 )
     825                        ) {
     826                                // reuse BasicType/EnumInstType common type by swapping
     827                                result = commonType( type2, enumInst, widen, symtab, tenv, open );
     828                        }
     829                }
     830
     831                void postvisit( const ast::TraitInstType * ) {}
     832
     833                void postvisit( const ast::TypeInstType * inst ) {
     834                        if ( ! widen.first ) return;
     835                        if ( const ast::NamedTypeDecl * nt = symtab.lookupType( inst->name ) ) {
     836                                if ( const ast::Type * base =
     837                                                strict_dynamic_cast< const ast::TypeDecl * >( nt )->base
     838                                ) {
     839                                        ast::CV::Qualifiers q1 = inst->qualifiers, q2 = type2->qualifiers;
     840
     841                                        // force t{1,2} to be cloned if their qualifiers must be mutated
     842                                        ast::ptr< ast::Type > t1{ base }, t2{ type2 };
     843                                        reset_qualifiers( t1, q1 );
     844                                        reset_qualifiers( t2 );
     845
     846                                        ast::AssertionSet have, need;
     847                                        ast::OpenVarSet newOpen{ open };
     848                                        if ( unifyExact( t1, t2, tenv, have, need, newOpen, noWiden(), symtab ) ) {
     849                                                result = type2;
     850                                                reset_qualifiers( result, q1 | q2 );
     851                                        }
     852                                }
     853                        }
     854                }
     855
     856                void postvisit( const ast::TupleType * ) {}
     857
     858                void postvisit( const ast::VarArgsType * ) {}
     859
     860                void postvisit( const ast::ZeroType * zero ) {
     861                        if ( ! widen.first ) return;
     862                        if (
     863                                dynamic_cast< const ast::BasicType * >( type2 )
     864                                || dynamic_cast< const ast::PointerType * >( type2 )
     865                                || dynamic_cast< const ast::EnumInstType * >( type2 )
     866                        ) {
     867                                if ( widen.second || zero->qualifiers <= type2->qualifiers ) {
     868                                        result = type2;
     869                                        add_qualifiers( result, zero->qualifiers );
     870                                }
     871                        } else if ( widen.second && dynamic_cast< const ast::OneType * >( type2 ) ) {
     872                                result = new ast::BasicType{
     873                                        ast::BasicType::SignedInt, zero->qualifiers | type2->qualifiers };
     874                        }
     875                }
     876
     877                void postvisit( const ast::OneType * one ) {
     878                        if ( ! widen.first ) return;
     879                        if (
     880                                dynamic_cast< const ast::BasicType * >( type2 )
     881                                || dynamic_cast< const ast::EnumInstType * >( type2 )
     882                        ) {
     883                                if ( widen.second || one->qualifiers <= type2->qualifiers ) {
     884                                        result = type2;
     885                                        add_qualifiers( result, one->qualifiers );
     886                                }
     887                        } else if ( widen.second && dynamic_cast< const ast::ZeroType * >( type2 ) ) {
     888                                result = new ast::BasicType{
     889                                        ast::BasicType::SignedInt, one->qualifiers | type2->qualifiers };
     890                        }
     891                }
     892
     893        };
     894
     895        namespace {
     896                ast::ptr< ast::Type > handleReference(
     897                        const ast::ptr< ast::Type > & t1, const ast::ptr< ast::Type > & t2, WidenMode widen,
     898                        const ast::SymbolTable & symtab, ast::TypeEnvironment & env,
     899                        const ast::OpenVarSet & open
     900                ) {
     901                        ast::ptr<ast::Type> common;
     902                        ast::AssertionSet have, need;
     903                        ast::OpenVarSet newOpen{ open };
     904
     905                        // need unify to bind type variables
     906                        if ( unify( t1, t2, env, have, need, newOpen, symtab, common ) ) {
     907                                ast::CV::Qualifiers q1 = t1->qualifiers, q2 = t2->qualifiers;
     908                                PRINT(
     909                                        std::cerr << "unify success: " << widenFirst << " " << widenSecond << std::endl;
     910                                )
     911                                if ( ( widen.first || q2 <= q1 ) && ( widen.second || q1 <= q2 ) ) {
     912                                        PRINT(
     913                                                std::cerr << "widen okay" << std::endl;
     914                                        )
     915                                        add_qualifiers( common, q1 | q2 );
     916                                        return common;
     917                                }
     918                        }
     919
     920                        PRINT(
     921                                std::cerr << "exact unify failed: " << t1 << " " << t2 << std::endl;
     922                        )
     923                        return { nullptr };
     924                }
     925        }
     926
     927        ast::ptr< ast::Type > commonType(
     928                        const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2,
     929                        WidenMode widen, const ast::SymbolTable & symtab, ast::TypeEnvironment & env,
     930                        const ast::OpenVarSet & open
     931        ) {
     932                unsigned depth1 = type1->referenceDepth();
     933                unsigned depth2 = type2->referenceDepth();
     934
     935                if ( depth1 != depth2 ) {  // implies depth1 > 0 || depth2 > 0
     936                        PRINT(
     937                                std::cerr << "reference depth diff: " << (depth1-depth2) << std::endl;
     938                        )
     939                        ast::ptr< ast::Type > result;
     940                        const ast::ReferenceType * ref1 = type1.as< ast::ReferenceType >();
     941                        const ast::ReferenceType * ref2 = type1.as< ast::ReferenceType >();
     942
     943                        if ( depth1 > depth2 ) {
     944                                assert( ref1 );
     945                                result = handleReference( ref1->base, type2, widen, symtab, env, open );
     946                        } else {  // implies depth1 < depth2
     947                                assert( ref2 );
     948                                result = handleReference( type1, ref2->base, widen, symtab, env, open );
     949                        }
     950
     951                        if ( result && ref1 ) {
     952                                // formal is reference, so result should be reference
     953                                PRINT(
     954                                        std::cerr << "formal is reference; result should be reference" << std::endl;
     955                                )
     956                                result = new ast::ReferenceType{ result, ref1->qualifiers };
     957                        }
     958
     959                        PRINT(
     960                                std::cerr << "common type of reference [" << type1 << "] and [" << type2 << "] is "
     961                                "[" << result << "]" << std::endl;
     962                        )
     963                        return result;
     964                }
     965                // otherwise both are reference types of the same depth and this is handled by the visitor
     966                ast::Pass<CommonType_new> visitor{ type2, widen, symtab, env, open };
     967                type1->accept( visitor );
     968                ast::ptr< ast::Type > result = visitor.pass.result;
     969
     970                // handling for opaque type declarations (?)
     971                if ( ! result && widen.second ) {
     972                        if ( const ast::TypeInstType * inst = type2.as< ast::TypeInstType >() ) {
     973                                if ( const ast::NamedTypeDecl * nt = symtab.lookupType( inst->name ) ) {
     974                                        auto type = strict_dynamic_cast< const ast::TypeDecl * >( nt );
     975                                        if ( type->base ) {
     976                                                ast::CV::Qualifiers q1 = type1->qualifiers, q2 = type2->qualifiers;
     977                                                ast::AssertionSet have, need;
     978                                                ast::OpenVarSet newOpen{ open };
     979
     980                                                // force t{1,2} to be cloned if its qualifiers must be stripped, so that
     981                                                // type1 and type->base are left unchanged; calling convention forces
     982                                                // {type1,type->base}->strong_ref >= 1
     983                                                ast::ptr<ast::Type> t1{ type1 }, t2{ type->base };
     984                                                reset_qualifiers( t1 );
     985                                                reset_qualifiers( t2, q1 );
     986
     987                                                if ( unifyExact( t1, t2, env, have, need, newOpen, noWiden(), symtab ) ) {
     988                                                        result = t1;
     989                                                        reset_qualifiers( result, q1 | q2 );
     990                                                }
     991                                        }
     992                                }
     993                        }
     994                }
     995
     996                return result;
     997        }
     998
    385999} // namespace ResolvExpr
    3861000
  • src/ResolvExpr/ConversionCost.cc

    r7951100 rb067d9b  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 07:06:19 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Sep 25 15:43:34 2017
    13 // Update Count     : 10
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Aug 12 10:21:00 2019
     13// Update Count     : 27
    1414//
    1515
     
    2828
    2929namespace ResolvExpr {
    30         const Cost Cost::zero =      Cost(  0,  0,  0,  0 );
    31         const Cost Cost::infinity =  Cost( -1, -1, -1, -1 );
    32         const Cost Cost::unsafe =    Cost(  1,  0,  0,  0 );
    33         const Cost Cost::poly =      Cost(  0,  1,  0,  0 );
    34         const Cost Cost::safe =      Cost(  0,  0,  1,  0 );
    35         const Cost Cost::reference = Cost(  0,  0,  0,  1 );
     30#if 0
     31        const Cost Cost::zero =      Cost{  0,  0,  0,  0,  0,  0,  0 };
     32        const Cost Cost::infinity =  Cost{ -1, -1, -1, -1, -1,  1, -1 };
     33        const Cost Cost::unsafe =    Cost{  1,  0,  0,  0,  0,  0,  0 };
     34        const Cost Cost::poly =      Cost{  0,  1,  0,  0,  0,  0,  0 };
     35        const Cost Cost::safe =      Cost{  0,  0,  1,  0,  0,  0,  0 };
     36        const Cost Cost::sign =      Cost{  0,  0,  0,  1,  0,  0,  0 };
     37        const Cost Cost::var =       Cost{  0,  0,  0,  0,  1,  0,  0 };
     38        const Cost Cost::spec =      Cost{  0,  0,  0,  0,  0, -1,  0 };
     39        const Cost Cost::reference = Cost{  0,  0,  0,  0,  0,  0,  1 };
     40#endif
    3641
    3742#if 0
     
    4045#define PRINT(x)
    4146#endif
    42         Cost conversionCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
    43                 if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) {
     47
     48        Cost conversionCost( const Type * src, const Type * dest, bool srcIsLvalue,
     49                        const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
     50                if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType * >( dest ) ) {
    4451                        PRINT( std::cerr << "type inst " << destAsTypeInst->name; )
    45                         if ( const EqvClass* eqvClass = env.lookup( destAsTypeInst->name ) ) {
     52                        if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->name ) ) {
    4653                                if ( eqvClass->type ) {
    47                                         return conversionCost( src, eqvClass->type, indexer, env );
     54                                        return conversionCost( src, eqvClass->type, srcIsLvalue, indexer, env );
    4855                                } else {
    4956                                        return Cost::infinity;
    5057                                }
    51                         } else if ( NamedTypeDecl *namedType = indexer.lookupType( destAsTypeInst->name ) ) {
     58                        } else if ( const NamedTypeDecl * namedType = indexer.lookupType( destAsTypeInst->name ) ) {
    5259                                PRINT( std::cerr << " found" << std::endl; )
    53                                 TypeDecl *type = dynamic_cast< TypeDecl* >( namedType );
     60                                const TypeDecl * type = dynamic_cast< const TypeDecl * >( namedType );
    5461                                // all typedefs should be gone by this point
    5562                                assert( type );
    5663                                if ( type->base ) {
    57                                         return conversionCost( src, type->base, indexer, env ) + Cost::safe;
     64                                        return conversionCost( src, type->base, srcIsLvalue, indexer, env )
     65                                                + Cost::safe;
    5866                                } // if
    5967                        } // if
     
    7179                        PRINT( std::cerr << "compatible!" << std::endl; )
    7280                        return Cost::zero;
    73                 } else if ( dynamic_cast< VoidType* >( dest ) ) {
     81                } else if ( dynamic_cast< const VoidType * >( dest ) ) {
    7482                        return Cost::safe;
    75                 } else if ( ReferenceType * refType = dynamic_cast< ReferenceType * > ( dest ) ) {
     83                } else if ( const ReferenceType * refType = dynamic_cast< const ReferenceType * > ( dest ) ) {
    7684                        PRINT( std::cerr << "conversionCost: dest is reference" << std::endl; )
    77                         return convertToReferenceCost( src, refType, indexer, env, [](Type * t1, Type * t2, const SymTab::Indexer &, const TypeEnvironment & env ){
     85                        return convertToReferenceCost( src, refType, srcIsLvalue, indexer, env, [](const Type * const t1, const Type * t2, const SymTab::Indexer &, const TypeEnvironment & env ){
    7886                                return ptrsAssignable( t1, t2, env );
    7987                        });
    8088                } else {
    81                         PassVisitor<ConversionCost> converter( dest, indexer, env, conversionCost );
     89                        PassVisitor<ConversionCost> converter(
     90                                dest, srcIsLvalue, indexer, env,
     91                                (Cost (*)(const Type *, const Type *, bool, const SymTab::Indexer&, const TypeEnvironment&))
     92                                        conversionCost );
    8293                        src->accept( converter );
    8394                        if ( converter.pass.get_cost() == Cost::infinity ) {
     
    89100        }
    90101
    91         Cost convertToReferenceCost( Type * src, Type * dest, int diff, const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {
     102        static Cost convertToReferenceCost( const Type * src, const Type * dest, bool srcIsLvalue,
     103                        int diff, const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {
    92104                PRINT( std::cerr << "convert to reference cost... diff " << diff << " " << src << " / " << dest << std::endl; )
    93105                if ( diff > 0 ) {
    94106                        // TODO: document this
    95                         Cost cost = convertToReferenceCost( strict_dynamic_cast< ReferenceType * >( src )->base, dest, diff-1, indexer, env, func );
     107                        Cost cost = convertToReferenceCost(
     108                                strict_dynamic_cast< const ReferenceType * >( src )->base, dest, srcIsLvalue,
     109                                diff-1, indexer, env, func );
    96110                        cost.incReference();
    97111                        return cost;
    98112                } else if ( diff < -1 ) {
    99113                        // TODO: document this
    100                         Cost cost = convertToReferenceCost( src, strict_dynamic_cast< ReferenceType * >( dest )->base, diff+1, indexer, env, func );
     114                        Cost cost = convertToReferenceCost(
     115                                src, strict_dynamic_cast< const ReferenceType * >( dest )->base, srcIsLvalue,
     116                                diff+1, indexer, env, func );
    101117                        cost.incReference();
    102118                        return cost;
    103119                } else if ( diff == 0 ) {
    104                         ReferenceType * srcAsRef = dynamic_cast< ReferenceType * >( src );
    105                         ReferenceType * destAsRef = dynamic_cast< ReferenceType * >( dest );
     120                        const ReferenceType * srcAsRef = dynamic_cast< const ReferenceType * >( src );
     121                        const ReferenceType * destAsRef = dynamic_cast< const ReferenceType * >( dest );
    106122                        if ( srcAsRef && destAsRef ) { // pointer-like conversions between references
    107123                                PRINT( std::cerr << "converting between references" << std::endl; )
    108                                 Type::Qualifiers tq1 = srcAsRef->base->get_qualifiers();
    109                                 Type::Qualifiers tq2 = destAsRef->base->get_qualifiers();
     124                                Type::Qualifiers tq1 = srcAsRef->base->tq;
     125                                Type::Qualifiers tq2 = destAsRef->base->tq;
    110126                                if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( srcAsRef->base, destAsRef->base, indexer, env ) ) {
    111127                                        PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )
     
    128144                        } else {
    129145                                PRINT( std::cerr << "reference to rvalue conversion" << std::endl; )
    130                                 PassVisitor<ConversionCost> converter( dest, indexer, env, conversionCost );
     146                                PassVisitor<ConversionCost> converter(
     147                                        dest, srcIsLvalue, indexer, env,
     148                                        (Cost (*)(const Type *, const Type *, bool, const SymTab::Indexer&, const TypeEnvironment&))
     149                                                conversionCost );
    131150                                src->accept( converter );
    132151                                return converter.pass.get_cost();
    133152                        } // if
    134153                } else {
    135                         ReferenceType * destAsRef = dynamic_cast< ReferenceType * >( dest );
     154                        const ReferenceType * destAsRef = dynamic_cast< const ReferenceType * >( dest );
    136155                        assert( diff == -1 && destAsRef );
    137156                        PRINT( std::cerr << "dest is: " << dest << " / src is: " << src << std::endl; )
    138157                        if ( typesCompatibleIgnoreQualifiers( src, destAsRef->base, indexer, env ) ) {
    139158                                PRINT( std::cerr << "converting compatible base type" << std::endl; )
    140                                 if ( src->get_lvalue() ) {
     159                                if ( srcIsLvalue ) {
    141160                                        PRINT(
    142161                                                std::cerr << "lvalue to reference conversion" << std::endl;
     
    144163                                        )
    145164                                        // lvalue-to-reference conversion:  cv lvalue T => cv T &
    146                                         if ( src->get_qualifiers() == destAsRef->base->get_qualifiers() ) {
     165                                        if ( src->tq == destAsRef->base->tq ) {
    147166                                                return Cost::reference; // cost needs to be non-zero to add cast
    148                                         } if ( src->get_qualifiers() < destAsRef->base->get_qualifiers() ) {
     167                                        } if ( src->tq < destAsRef->base->tq ) {
    149168                                                return Cost::safe; // cost needs to be higher than previous cast to differentiate adding qualifiers vs. keeping same
    150169                                        } else {
     
    166185        }
    167186
    168         Cost convertToReferenceCost( Type * src, ReferenceType * dest, const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {
     187        Cost convertToReferenceCost( const Type * src, const ReferenceType * dest, bool srcIsLvalue,
     188                        const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func ) {
    169189                int sdepth = src->referenceDepth(), ddepth = dest->referenceDepth();
    170                 Cost cost = convertToReferenceCost( src, dest, sdepth-ddepth, indexer, env, func );
     190                Cost cost = convertToReferenceCost( src, dest, srcIsLvalue, sdepth-ddepth, indexer, env, func );
    171191                PRINT( std::cerr << "convertToReferenceCost result: " << cost << std::endl; )
    172192                return cost;
    173193        }
    174194
    175         ConversionCost::ConversionCost( Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc )
    176                 : dest( dest ), indexer( indexer ), cost( Cost::infinity ), env( env ), costFunc( costFunc ) {
    177         }
    178 
    179 /*
    180             Old
    181             ===
    182            Double
    183              |
    184            Float
    185              |
    186            ULong
    187            /   \
    188         UInt    Long
    189            \   /
    190             Int
    191              |
    192            Ushort
    193              |
    194            Short
    195              |
    196            Uchar
    197            /   \
    198         Schar   Char
    199 
    200                                 New
    201                                 ===
    202                        +-----LongDoubleComplex--+
    203            LongDouble--+          |             +-LongDoubleImag
    204              |         +---DoubleComplex---+         |
    205            Double------+        |          +----DoubleImag
    206              |           +-FloatComplex-+            |
    207            Float---------+              +-------FloatImag
    208              |
    209           ULongLong
    210              |
    211           LongLong
    212              |
    213            ULong
    214            /   \
    215         UInt    Long
    216            \   /
    217             Int
    218              |
    219            Ushort
    220              |
    221            Short
    222              |
    223            Uchar
    224            /   \
    225         Schar   Char
    226            \   /
    227             Bool
    228 */
    229 
    230         static const int costMatrix[][ BasicType::NUMBER_OF_BASIC_TYPES ] = {
    231         /* Src \ Dest:  Bool    Char    SChar   UChar   Short   UShort  Int     UInt    Long    ULong   LLong   ULLong  Float   Double  LDbl    FCplex  DCplex  LDCplex FImag   DImag   LDImag  I128,   U128, F80, F128 */
    232                 /* Bool */      { 0,    1,              1,              2,              3,              4,              5,              6,              6,              7,              8,              9,              12,             13,             14,             12,             13,             14,             -1,             -1,             -1,             10,             11,       14,   15},
    233                 /* Char */      { -1,   0,              -1,             1,              2,              3,              4,              5,              5,              6,              7,              8,              11,             12,             13,             11,             12,             13,             -1,             -1,             -1,             9,              10,       13,   14},
    234                 /* SChar */ { -1,       -1,             0,              1,              2,              3,              4,              5,              5,              6,              7,              8,              11,             12,             13,             11,             12,             13,             -1,             -1,             -1,             9,              10,       13,   14},
    235                 /* UChar */ { -1,       -1,             -1,             0,              1,              2,              3,              4,              4,              5,              6,              7,              10,             11,             12,             10,             11,             12,             -1,             -1,             -1,             8,              9,        12,   13},
    236                 /* Short */ { -1,       -1,             -1,             -1,             0,              1,              2,              3,              3,              4,              5,              6,              9,              10,             11,             9,              10,             11,             -1,             -1,             -1,             7,              8,        11,   12},
    237                 /* UShort */{ -1,       -1,             -1,             -1,             -1,             0,              1,              2,              2,              3,              4,              5,              8,              9,              10,             8,              9,              10,             -1,             -1,             -1,             6,              7,        10,   11},
    238                 /* Int */       { -1,   -1,             -1,             -1,             -1,             -1,             0,              1,              1,              2,              3,              4,              7,              8,              9,              7,              8,              9,              -1,             -1,             -1,             5,              6,        9,    10},
    239                 /* UInt */      { -1,   -1,             -1,             -1,             -1,             -1,             -1,             0,              -1,             1,              2,              3,              6,              7,              8,              6,              7,              8,              -1,             -1,             -1,             4,              5,        8,    9},
    240                 /* Long */      { -1,   -1,             -1,             -1,             -1,             -1,             -1,             -1,             0,              1,              2,              3,              6,              7,              8,              6,              7,              8,              -1,             -1,             -1,             4,              5,        8,    9},
    241                 /* ULong */ { -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             0,              1,              2,              5,              6,              7,              5,              6,              7,              -1,             -1,             -1,             3,              4,        7,    8},
    242                 /* LLong */ { -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             0,              1,              4,              5,              6,              4,              5,              6,              -1,             -1,             -1,             2,              3,        6,    7},
    243                 /* ULLong */{ -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             0,              3,              4,              5,              3,              4,              5,              -1,             -1,             -1,             1,              2,        5,    6},
    244 
    245                 /* Float */ { -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             0,              1,              2,              1,              2,              3,              -1,             -1,             -1,             -1,             -1,       2,    3},
    246                 /* Double */{ -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             0,              1,              -1,             1,              2,              -1,             -1,             -1,             -1,             -1,       1,    2},
    247                 /* LDbl */      { -1,   -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             0,              -1,             -1,             1,              -1,             -1,             -1,             -1,             -1,       -1,   1},
    248                 /* FCplex */{ -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             0,              1,              2,              -1,             -1,             -1,             -1,             -1,       -1,   -1},
    249                 /* DCplex */{ -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             0,              1,              -1,             -1,             -1,             -1,             -1,       -1,   -1},
    250                 /* LDCplex */{ -1,      -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             0,              -1,             -1,             -1,             -1,             -1,       -1,   -1},
    251                 /* FImag */ { -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             1,              2,              3,              0,              1,              2,              -1,             -1,       -1,   -1},
    252                 /* DImag */ { -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             1,              2,              -1,             0,              1,              -1,             -1,       -1,   -1},
    253                 /* LDImag */{ -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             1,              -1,             -1,             0,              -1,             -1,       -1,   -1},
    254 
    255                 /* I128 */  { -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             2,              3,              4,              3,              4,              5,              -1,             -1,             -1,             0,              1,        4,    4},
    256                 /* U128 */  { -1,       -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             1,              2,              3,              2,              3,              4,              -1,             -1,             -1,             -1,             0,        3,    3},
    257 
    258                 /* F80 */       { -1,   -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             1,              -1,             -1,             1,              -1,             -1,             -1,             -1,             -1,       0,    1},
    259                 /* F128 */      { -1,   -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             -1,             1,              -1,             -1,             -1,             -1,             -1,       -1,   0},
    260         };
     195        ConversionCost::ConversionCost( const Type * dest, bool srcIsLvalue, const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction costFunc )
     196                : dest( dest ), srcIsLvalue( srcIsLvalue ), indexer( indexer ), cost( Cost::infinity ), env( env ), costFunc( costFunc ) {
     197        }
     198
     199        // GENERATED START, DO NOT EDIT
     200        // GENERATED BY BasicTypes-gen.cc
     201        /* EXTENDED INTEGRAL RANK HIERARCHY (root to leaves)
     202                                 _Bool
     203        char                signed char         unsigned char
     204                  signed short int         unsigned short int
     205                  signed int               unsigned int
     206                  signed long int          unsigned long int
     207                  signed long long int     unsigned long long int
     208                  __int128                 unsigned __int128
     209                  _Float16                 _Float16 _Complex
     210                  _Float32                 _Float32 _Complex
     211                  float                    float _Complex
     212                  _Float32x                _Float32x _Complex
     213                  _Float64                 _Float64 _Complex
     214                  double                   double _Complex
     215                  _Float64x                _Float64x _Complex
     216                             __float80
     217                  _Float128                _Float128 _Complex
     218                            __float128
     219                  long double              long double _Complex
     220                  _Float128x               _Float128x _Complex
     221        */
     222        // GENERATED END
     223
     224        // GENERATED START, DO NOT EDIT
     225        // GENERATED BY BasicTypes-gen.cc
     226        static const int costMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // path length from root to node
     227                /*               B    C   SC   UC   SI  SUI    I   UI   LI  LUI  LLI LLUI   IB  UIB  _FH  _FH   _F  _FC    F   FC  _FX _FXC   FD _FDC    D   DC F80X_FDXC  F80  _FB_FLDC   FB   LD  LDC _FBX_FLDXC */
     228                /*      B */ {   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  15,  16,  17,  16,  18,  17, },
     229                /*      C */ {  -1,   0,   1,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  16,  15,  17,  16, },
     230                /*     SC */ {  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  16,  15,  17,  16, },
     231                /*     UC */ {  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  14,  15,  16,  15,  17,  16, },
     232                /*     SI */ {  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  15,  14,  16,  15, },
     233                /*    SUI */ {  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  13,  14,  15,  14,  16,  15, },
     234                /*      I */ {  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  14,  13,  15,  14, },
     235                /*     UI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,  14,  13,  15,  14, },
     236                /*     LI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  13,  12,  14,  13, },
     237                /*    LUI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  13,  12,  14,  13, },
     238                /*    LLI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  12,  11,  13,  12, },
     239                /*   LLUI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  10,  11,  12,  11,  13,  12, },
     240                /*     IB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  11,  10,  12,  11, },
     241                /*    UIB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,   9,  10,  11,  10,  12,  11, },
     242                /*    _FH */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   8,   9,  10,   9,  11,  10, },
     243                /*    _FH */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,  -1,   4,  -1,   5,  -1,   6,  -1,  -1,   7,  -1,  -1,   8,  -1,   9, },
     244                /*     _F */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   8,   9,   8,  10,   9, },
     245                /*    _FC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,  -1,   4,  -1,   5,  -1,  -1,   6,  -1,  -1,   7,  -1,   8, },
     246                /*      F */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   8,   7,   9,   8, },
     247                /*     FC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,  -1,   4,  -1,  -1,   5,  -1,  -1,   6,  -1,   7, },
     248                /*    _FX */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   7,   6,   8,   7, },
     249                /*   _FXC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,   3,  -1,  -1,   4,  -1,  -1,   5,  -1,   6, },
     250                /*     FD */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   6,   5,   7,   6, },
     251                /*   _FDC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,   2,  -1,  -1,   3,  -1,  -1,   4,  -1,   5, },
     252                /*      D */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3,   4,   5,   4,   6,   5, },
     253                /*     DC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1,  -1,  -1,   2,  -1,  -1,   3,  -1,   4, },
     254                /*   F80X */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   4,   3,   5,   4, },
     255                /*  _FDXC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   1,  -1,  -1,   2,  -1,   3, },
     256                /*    F80 */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   1,   0,   1,   2,   2,   3,   3,   4,   4, },
     257                /*    _FB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   2,   3,   3, },
     258                /*  _FLDC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   1,  -1,   2, },
     259                /*     FB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   1,   0,   1,   2,   2,   3, },
     260                /*     LD */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   2, },
     261                /*    LDC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   1, },
     262                /*   _FBX */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1, },
     263                /* _FLDXC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0, },
     264        }; // costMatrix
     265        static const int maxIntCost = 15;
     266        // GENERATED END
    261267        static_assert(
    262                 sizeof(costMatrix)/sizeof(costMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES*BasicType::NUMBER_OF_BASIC_TYPES,
    263                 "Each basic type kind should have a corresponding row in the cost matrix"
     268                sizeof(costMatrix)/sizeof(costMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES * BasicType::NUMBER_OF_BASIC_TYPES,
     269                "Missing row in the cost matrix"
    264270        );
    265271
    266 
    267         void ConversionCost::postvisit( VoidType * ) {
     272        // GENERATED START, DO NOT EDIT
     273        // GENERATED BY BasicTypes-gen.cc
     274        static const int signMatrix[BasicType::NUMBER_OF_BASIC_TYPES][BasicType::NUMBER_OF_BASIC_TYPES] = { // number of sign changes in safe conversion
     275                /*               B    C   SC   UC   SI  SUI    I   UI   LI  LUI  LLI LLUI   IB  UIB  _FH  _FH   _F  _FC    F   FC  _FX _FXC   FD _FDC    D   DC F80X_FDXC  F80  _FB_FLDC   FB   LD  LDC _FBX_FLDXC */
     276                /*      B */ {   0,   0,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     277                /*      C */ {  -1,   0,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     278                /*     SC */ {  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     279                /*     UC */ {  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     280                /*     SI */ {  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     281                /*    SUI */ {  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     282                /*      I */ {  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     283                /*     UI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     284                /*     LI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     285                /*    LUI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     286                /*    LLI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     287                /*   LLUI */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     288                /*     IB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     289                /*    UIB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     290                /*    _FH */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     291                /*    _FH */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
     292                /*     _F */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     293                /*    _FC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
     294                /*      F */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     295                /*     FC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
     296                /*    _FX */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     297                /*   _FXC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
     298                /*     FD */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     299                /*   _FDC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
     300                /*      D */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     301                /*     DC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
     302                /*   F80X */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     303                /*  _FDXC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
     304                /*    F80 */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   0, },
     305                /*    _FB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0,   0, },
     306                /*  _FLDC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   0,  -1,   0, },
     307                /*     FB */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,   0, },
     308                /*     LD */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0, },
     309                /*    LDC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0, },
     310                /*   _FBX */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0, },
     311                /* _FLDXC */ {  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0, },
     312        }; // signMatrix
     313        // GENERATED END
     314        static_assert(
     315                sizeof(signMatrix)/sizeof(signMatrix[0][0]) == BasicType::NUMBER_OF_BASIC_TYPES * BasicType::NUMBER_OF_BASIC_TYPES,
     316                "Missing row in the sign matrix"
     317        );
     318
     319        void ConversionCost::postvisit( const VoidType * ) {
    268320                cost = Cost::infinity;
    269321        }
    270322
    271         void ConversionCost::postvisit(BasicType *basicType) {
    272                 if ( BasicType *destAsBasic = dynamic_cast< BasicType* >( dest ) ) {
    273                         int tableResult = costMatrix[ basicType->get_kind() ][ destAsBasic->get_kind() ];
     323        void ConversionCost::postvisit(const BasicType * basicType) {
     324                if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {
     325                        int tableResult = costMatrix[ basicType->kind ][ destAsBasic->kind ];
    274326                        if ( tableResult == -1 ) {
    275327                                cost = Cost::unsafe;
     
    277329                                cost = Cost::zero;
    278330                                cost.incSafe( tableResult );
    279                         } // if
    280                 } else if ( dynamic_cast< EnumInstType *>( dest ) ) {
     331                                cost.incSign( signMatrix[ basicType->kind ][ destAsBasic->kind ] );
     332                        } // if
     333                } else if ( dynamic_cast< const EnumInstType * >( dest ) ) {
    281334                        // xxx - not positive this is correct, but appears to allow casting int => enum
    282335                        cost = Cost::unsafe;
     
    285338        }
    286339
    287         void ConversionCost::postvisit( PointerType * pointerType ) {
    288                 if ( PointerType *destAsPtr = dynamic_cast< PointerType* >( dest ) ) {
     340        void ConversionCost::postvisit( const PointerType * pointerType ) {
     341                if ( const PointerType * destAsPtr = dynamic_cast< const PointerType * >( dest ) ) {
    289342                        PRINT( std::cerr << pointerType << " ===> " << destAsPtr << std::endl; )
    290                         Type::Qualifiers tq1 = pointerType->base->get_qualifiers();
    291                         Type::Qualifiers tq2 = destAsPtr->base->get_qualifiers();
     343                        Type::Qualifiers tq1 = pointerType->base->tq;
     344                        Type::Qualifiers tq2 = destAsPtr->base->tq;
    292345                        if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers( pointerType->base, destAsPtr->base, indexer, env ) ) {
    293346                                PRINT( std::cerr << " :: compatible and good qualifiers" << std::endl; )
     
    298351                                        // types are the same, except otherPointer has more qualifiers
    299352                                        cost = Cost::safe;
    300                                 }
     353                                } // if
    301354                        } else {
    302355                                int assignResult = ptrsAssignable( pointerType->base, destAsPtr->base, env );
     
    318371        }
    319372
    320         void ConversionCost::postvisit( ArrayType * ) {}
    321 
    322         void ConversionCost::postvisit( ReferenceType * refType ) {
     373        void ConversionCost::postvisit( const ArrayType * ) {}
     374
     375        void ConversionCost::postvisit( const ReferenceType * refType ) {
    323376                // Note: dest can never be a reference, since it would have been caught in an earlier check
    324                 assert( ! dynamic_cast< ReferenceType * >( dest ) );
     377                assert( ! dynamic_cast< const ReferenceType * >( dest ) );
    325378                // convert reference to rvalue: cv T1 & => T2
    326379                // recursively compute conversion cost from T1 to T2.
    327380                // cv can be safely dropped because of 'implicit dereference' behavior.
    328                 cost = costFunc( refType->base, dest, indexer, env );
    329                 if ( refType->base->get_qualifiers() == dest->get_qualifiers() ) {
     381                cost = costFunc( refType->base, dest, srcIsLvalue, indexer, env );
     382                if ( refType->base->tq == dest->tq ) {
    330383                        cost.incReference();  // prefer exact qualifiers
    331                 } else if ( refType->base->get_qualifiers() < dest->get_qualifiers() ) {
     384                } else if ( refType->base->tq < dest->tq ) {
    332385                        cost.incSafe(); // then gaining qualifiers
    333386                } else {
     
    337390        }
    338391
    339         void ConversionCost::postvisit( FunctionType * ) {}
    340 
    341         void ConversionCost::postvisit( StructInstType * inst ) {
    342                 if ( StructInstType *destAsInst = dynamic_cast< StructInstType* >( dest ) ) {
     392        void ConversionCost::postvisit( const FunctionType * ) {}
     393
     394        void ConversionCost::postvisit( const StructInstType * inst ) {
     395                if ( const StructInstType * destAsInst = dynamic_cast< const StructInstType * >( dest ) ) {
    343396                        if ( inst->name == destAsInst->name ) {
    344397                                cost = Cost::zero;
     
    347400        }
    348401
    349         void ConversionCost::postvisit( UnionInstType * inst ) {
    350                 if ( UnionInstType *destAsInst = dynamic_cast< UnionInstType* >( dest ) ) {
     402        void ConversionCost::postvisit( const UnionInstType * inst ) {
     403                if ( const UnionInstType * destAsInst = dynamic_cast< const UnionInstType * >( dest ) ) {
    351404                        if ( inst->name == destAsInst->name ) {
    352405                                cost = Cost::zero;
     
    355408        }
    356409
    357         void ConversionCost::postvisit( EnumInstType * ) {
     410        void ConversionCost::postvisit( const EnumInstType * ) {
    358411                static Type::Qualifiers q;
    359412                static BasicType integer( q, BasicType::SignedInt );
    360                 cost = costFunc( &integer, dest, indexer, env );  // safe if dest >= int
     413                cost = costFunc( &integer, dest, srcIsLvalue, indexer, env );  // safe if dest >= int
    361414                if ( cost < Cost::unsafe ) {
    362415                        cost.incSafe();
     
    364417        }
    365418
    366         void ConversionCost::postvisit( TraitInstType * ) {}
    367 
    368         void ConversionCost::postvisit( TypeInstType *inst ) {
    369                 if ( const EqvClass *eqvClass = env.lookup( inst->name ) ) {
    370                         cost = costFunc( eqvClass->type, dest, indexer, env );
    371                 } else if ( TypeInstType *destAsInst = dynamic_cast< TypeInstType* >( dest ) ) {
     419        void ConversionCost::postvisit( const TraitInstType * ) {}
     420
     421        void ConversionCost::postvisit( const TypeInstType * inst ) {
     422                if ( const EqvClass * eqvClass = env.lookup( inst->name ) ) {
     423                        cost = costFunc( eqvClass->type, dest, srcIsLvalue, indexer, env );
     424                } else if ( const TypeInstType * destAsInst = dynamic_cast< const TypeInstType * >( dest ) ) {
    372425                        if ( inst->name == destAsInst->name ) {
    373426                                cost = Cost::zero;
    374427                        }
    375                 } else if ( NamedTypeDecl *namedType = indexer.lookupType( inst->name ) ) {
    376                         TypeDecl *type = dynamic_cast< TypeDecl* >( namedType );
     428                } else if ( const NamedTypeDecl * namedType = indexer.lookupType( inst->name ) ) {
     429                        const TypeDecl * type = dynamic_cast< const TypeDecl * >( namedType );
    377430                        // all typedefs should be gone by this point
    378431                        assert( type );
    379432                        if ( type->base ) {
    380                                 cost = costFunc( type->base, dest, indexer, env ) + Cost::safe;
    381                         } // if
    382                 } // if
    383         }
    384 
    385         void ConversionCost::postvisit( TupleType * tupleType ) {
     433                                cost = costFunc( type->base, dest, srcIsLvalue, indexer, env ) + Cost::safe;
     434                        } // if
     435                } // if
     436        }
     437
     438        void ConversionCost::postvisit( const TupleType * tupleType ) {
    386439                Cost c = Cost::zero;
    387                 if ( TupleType * destAsTuple = dynamic_cast< TupleType * >( dest ) ) {
     440                if ( const TupleType * destAsTuple = dynamic_cast< const TupleType * >( dest ) ) {
    388441                        std::list< Type * >::const_iterator srcIt = tupleType->types.begin();
    389442                        std::list< Type * >::const_iterator destIt = destAsTuple->types.begin();
    390443                        while ( srcIt != tupleType->types.end() && destIt != destAsTuple->types.end() ) {
    391                                 Cost newCost = costFunc( *srcIt++, *destIt++, indexer, env );
     444                                Cost newCost = costFunc( * srcIt++, * destIt++, srcIsLvalue, indexer, env );
    392445                                if ( newCost == Cost::infinity ) {
    393446                                        return;
     
    403456        }
    404457
    405         void ConversionCost::postvisit( VarArgsType * ) {
    406                 if ( dynamic_cast< VarArgsType* >( dest ) ) {
    407                         cost = Cost::zero;
    408                 }
    409         }
    410 
    411         void ConversionCost::postvisit( ZeroType * ) {
    412                 if ( dynamic_cast< ZeroType * >( dest ) ) {
    413                         cost = Cost::zero;
    414                 } else if ( BasicType *destAsBasic = dynamic_cast< BasicType* >( dest ) ) {
    415                         // copied from visit(BasicType*) for signed int, but +1 for safe conversions
    416                         int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ];
     458        void ConversionCost::postvisit( const VarArgsType * ) {
     459                if ( dynamic_cast< const VarArgsType * >( dest ) ) {
     460                        cost = Cost::zero;
     461                }
     462        }
     463
     464        void ConversionCost::postvisit( const ZeroType * ) {
     465                if ( dynamic_cast< const ZeroType * >( dest ) ) {
     466                        cost = Cost::zero;
     467                } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {
     468                        // copied from visit(BasicType *) for signed int, but +1 for safe conversions
     469                        int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->kind ];
    417470                        if ( tableResult == -1 ) {
    418471                                cost = Cost::unsafe;
     
    420473                                cost = Cost::zero;
    421474                                cost.incSafe( tableResult + 1 );
    422                         }
    423                 } else if ( dynamic_cast< PointerType* >( dest ) ) {
    424                         cost = Cost::safe;
    425                 }
    426         }
    427 
    428         void ConversionCost::postvisit( OneType * ) {
    429                 if ( dynamic_cast< OneType * >( dest ) ) {
    430                         cost = Cost::zero;
    431                 } else if ( BasicType *destAsBasic = dynamic_cast< BasicType* >( dest ) ) {
    432                         // copied from visit(BasicType*) for signed int, but +1 for safe conversions
    433                         int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->get_kind() ];
     475                                cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->kind ] );
     476                        } // if
     477                } else if ( dynamic_cast< const PointerType * >( dest ) ) {
     478                        cost = Cost::zero;
     479                        cost.incSafe( maxIntCost + 2 ); // +1 for zero_t -> int, +1 for disambiguation
     480                } // if
     481        }
     482
     483        void ConversionCost::postvisit( const OneType * ) {
     484                if ( dynamic_cast< const OneType * >( dest ) ) {
     485                        cost = Cost::zero;
     486                } else if ( const BasicType * destAsBasic = dynamic_cast< const BasicType * >( dest ) ) {
     487                        // copied from visit(BasicType *) for signed int, but +1 for safe conversions
     488                        int tableResult = costMatrix[ BasicType::SignedInt ][ destAsBasic->kind ];
    434489                        if ( tableResult == -1 ) {
    435490                                cost = Cost::unsafe;
     
    437492                                cost = Cost::zero;
    438493                                cost.incSafe( tableResult + 1 );
     494                                cost.incSign( signMatrix[ BasicType::SignedInt ][ destAsBasic->kind ] );
     495                        } // if
     496                } // if
     497        }
     498
     499static int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2,
     500                const ast::SymbolTable &, const ast::TypeEnvironment & env ) {
     501        return ptrsAssignable( t1, t2, env );
     502}
     503
     504// TODO: This is used for overload resolution. It might be able to be dropped once the old system
     505// is removed.
     506static Cost localConversionCost(
     507        const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
     508        const ast::TypeEnvironment & env
     509) { return conversionCost( src, dst, symtab, env ); }
     510
     511Cost conversionCost(
     512        const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
     513        const ast::TypeEnvironment & env
     514) {
     515        if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
     516                if ( const ast::EqvClass * eqv = env.lookup( inst->name ) ) {
     517                        if ( eqv->bound ) {
     518                                return conversionCost(src, eqv->bound, symtab, env );
     519                        } else {
     520                                return Cost::infinity;
    439521                        }
    440                 }
    441         }
     522                } else if ( const ast::NamedTypeDecl * named = symtab.lookupType( inst->name ) ) {
     523                        const ast::TypeDecl * type = dynamic_cast< const ast::TypeDecl * >( named );
     524                        assertf( type, "Unexpected typedef." );
     525                        if ( type->base ) {
     526                                return conversionCost( src, type->base, symtab, env ) + Cost::safe;
     527                        }
     528                }
     529        }
     530        if ( typesCompatibleIgnoreQualifiers( src, dst, symtab, env ) ) {
     531                return Cost::zero;
     532        } else if ( dynamic_cast< const ast::VoidType * >( dst ) ) {
     533                return Cost::safe;
     534        } else if ( const ast::ReferenceType * refType =
     535                         dynamic_cast< const ast::ReferenceType * >( dst ) ) {
     536                return convertToReferenceCost( src, refType, symtab, env, localPtrsAssignable );
     537        } else {
     538                ast::Pass<ConversionCost_new> converter( dst, symtab, env, localConversionCost );
     539                src->accept( converter );
     540                return converter.pass.cost;
     541        }
     542}
     543
     544static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst,
     545                int diff, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
     546                NumCostCalculation func ) {
     547        if ( 0 < diff ) {
     548                Cost cost = convertToReferenceCost(
     549                        strict_dynamic_cast< const ast::ReferenceType * >( src )->base,
     550                        dst, (diff - 1), symtab, env, func );
     551                cost.incReference();
     552                return cost;
     553        } else if ( diff < -1 ) {
     554                Cost cost = convertToReferenceCost(
     555                        src, strict_dynamic_cast< const ast::ReferenceType * >( dst )->base,
     556                        (diff + 1), symtab, env, func );
     557                cost.incReference();
     558                return cost;
     559        } else if ( 0 == diff ) {
     560                const ast::ReferenceType * srcAsRef = dynamic_cast< const ast::ReferenceType * >( src );
     561                const ast::ReferenceType * dstAsRef = dynamic_cast< const ast::ReferenceType * >( dst );
     562                if ( srcAsRef && dstAsRef ) {
     563                        ast::CV::Qualifiers tq1 = srcAsRef->base->qualifiers;
     564                        ast::CV::Qualifiers tq2 = dstAsRef->base->qualifiers;
     565                        if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers(
     566                                        srcAsRef->base, dstAsRef->base, symtab, env ) ) {
     567                                if ( tq1 == tq2 ) {
     568                                        return Cost::zero;
     569                                } else {
     570                                        return Cost::safe;
     571                                }
     572                        } else {
     573                                int assignResult = func( srcAsRef->base, dstAsRef->base, symtab, env );
     574                                if ( 0 < assignResult ) {
     575                                        return Cost::safe;
     576                                } else if ( assignResult < 0 ) {
     577                                        return Cost::unsafe;
     578                                }
     579                        }
     580                } else {
     581                        ast::Pass<ConversionCost_new> converter( dst, symtab, env, localConversionCost );
     582                        src->accept( converter );
     583                        return converter.pass.cost;
     584                }
     585        } else {
     586                assert( -1 == diff );
     587                const ast::ReferenceType * dstAsRef = dynamic_cast< const ast::ReferenceType * >( dst );
     588                assert( dstAsRef );
     589                if ( typesCompatibleIgnoreQualifiers( src, dstAsRef->base, symtab, env ) ) {
     590                        if ( src->is_lvalue() ) {
     591                                if ( src->qualifiers == dstAsRef->base->qualifiers ) {
     592                                        return Cost::reference;
     593                                } else if ( src->qualifiers < dstAsRef->base->qualifiers ) {
     594                                        return Cost::safe;
     595                                } else {
     596                                        return Cost::unsafe;
     597                                }
     598                        } else if ( dstAsRef->base->is_const() ) {
     599                                return Cost::safe;
     600                        } else {
     601                                return Cost::unsafe;
     602                        }
     603                }
     604        }
     605        return Cost::infinity;
     606}
     607
     608Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dst,
     609            const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
     610                NumCostCalculation func ) {
     611        int sdepth = src->referenceDepth(), ddepth = dst->referenceDepth();
     612        return convertToReferenceCost( src, dst, sdepth - ddepth, symtab, env, func );
     613}
     614
     615void ConversionCost_new::postvisit( const ast::VoidType * voidType ) {
     616        (void)voidType;
     617        cost = Cost::infinity;
     618}
     619
     620void ConversionCost_new::postvisit( const ast::BasicType * basicType ) {
     621        if ( const ast::BasicType * dstAsBasic = dynamic_cast< const ast::BasicType * >( dst ) ) {
     622                int tableResult = costMatrix[ basicType->kind ][ dstAsBasic->kind ];
     623                if ( tableResult == -1 ) {
     624                        cost = Cost::unsafe;
     625                } else {
     626                        cost = Cost::zero;
     627                        cost.incSafe( tableResult );
     628                        cost.incSign( signMatrix[ basicType->kind ][ dstAsBasic->kind ] );
     629                }
     630        } else if ( dynamic_cast< const ast::EnumInstType * >( dst ) ) {
     631                // xxx - not positive this is correct, but appears to allow casting int => enum
     632                cost = Cost::unsafe;
     633        }
     634}
     635
     636void ConversionCost_new::postvisit( const ast::PointerType * pointerType ) {
     637        if ( const ast::PointerType * dstAsPtr = dynamic_cast< const ast::PointerType * >( dst ) ) {
     638                ast::CV::Qualifiers tq1 = pointerType->base->qualifiers;
     639                ast::CV::Qualifiers tq2 = dstAsPtr->base->qualifiers;
     640                if ( tq1 <= tq2 && typesCompatibleIgnoreQualifiers(
     641                                pointerType->base, dstAsPtr->base, symtab, env ) ) {
     642                        if ( tq1 == tq2 ) {
     643                                cost = Cost::zero;
     644                        } else {
     645                                cost = Cost::safe;
     646                        }
     647                } else {
     648                        int assignResult = ptrsAssignable( pointerType->base, dstAsPtr->base, env );
     649                        if ( 0 < assignResult && tq1 <= tq2 ) {
     650                                if ( tq1 == tq2 ) {
     651                                        cost = Cost::safe;
     652                                } else {
     653                                        cost = Cost::safe + Cost::safe;
     654                                }
     655                        } else if ( assignResult < 0 ) {
     656                                cost = Cost::unsafe;
     657                        } // else Cost::infinity
     658                }
     659        }
     660}
     661
     662void ConversionCost_new::postvisit( const ast::ArrayType * arrayType ) {
     663        (void)arrayType;
     664}
     665
     666void ConversionCost_new::postvisit( const ast::ReferenceType * refType ) {
     667        assert( nullptr == dynamic_cast< const ast::ReferenceType * >( dst ) );
     668
     669        cost = costCalc( refType->base, dst, symtab, env );
     670        if ( refType->base->qualifiers == dst->qualifiers ) {
     671                cost.incReference();
     672        } else if ( refType->base->qualifiers < dst->qualifiers ) {
     673                cost.incSafe();
     674        } else {
     675                cost.incUnsafe();
     676        }
     677}
     678
     679void ConversionCost_new::postvisit( const ast::FunctionType * functionType ) {
     680        (void)functionType;
     681}
     682
     683void ConversionCost_new::postvisit( const ast::StructInstType * structInstType ) {
     684        if ( const ast::StructInstType * dstAsInst =
     685                        dynamic_cast< const ast::StructInstType * >( dst ) ) {
     686                if ( structInstType->name == dstAsInst->name ) {
     687                        cost = Cost::zero;
     688                }
     689        }
     690}
     691
     692void ConversionCost_new::postvisit( const ast::UnionInstType * unionInstType ) {
     693        if ( const ast::UnionInstType * dstAsInst =
     694                        dynamic_cast< const ast::UnionInstType * >( dst ) ) {
     695                if ( unionInstType->name == dstAsInst->name ) {
     696                        cost = Cost::zero;
     697                }
     698        }
     699}
     700
     701void ConversionCost_new::postvisit( const ast::EnumInstType * enumInstType ) {
     702        (void)enumInstType;
     703        static const ast::BasicType integer( ast::BasicType::SignedInt );
     704        cost = costCalc( &integer, dst, symtab, env );
     705        if ( cost < Cost::unsafe ) {
     706                cost.incSafe();
     707        }
     708}
     709
     710void ConversionCost_new::postvisit( const ast::TraitInstType * traitInstType ) {
     711        (void)traitInstType;
     712}
     713
     714void ConversionCost_new::postvisit( const ast::TypeInstType * typeInstType ) {
     715        if ( const ast::EqvClass * eqv = env.lookup( typeInstType->name ) ) {
     716                cost = costCalc( eqv->bound, dst, symtab, env );
     717        } else if ( const ast::TypeInstType * dstAsInst =
     718                        dynamic_cast< const ast::TypeInstType * >( dst ) ) {
     719                if ( typeInstType->name == dstAsInst->name ) {
     720                        cost = Cost::zero;
     721                }
     722        } else if ( const ast::NamedTypeDecl * namedType = symtab.lookupType( typeInstType->name ) ) {
     723                const ast::TypeDecl * type = dynamic_cast< const ast::TypeDecl * >( namedType );
     724                assertf( type, "Unexpected typedef.");
     725                if ( type->base ) {
     726                        cost = costCalc( type->base, dst, symtab, env ) + Cost::safe;
     727                }
     728        }
     729}
     730
     731void ConversionCost_new::postvisit( const ast::TupleType * tupleType ) {
     732        Cost c = Cost::zero;
     733        if ( const ast::TupleType * dstAsTuple = dynamic_cast< const ast::TupleType * >( dst ) ) {
     734                auto srcIt = tupleType->types.begin();
     735                auto dstIt = dstAsTuple->types.begin();
     736                auto srcEnd = tupleType->types.end();
     737                auto dstEnd = dstAsTuple->types.end();
     738                while ( srcIt != srcEnd && dstIt != dstEnd ) {
     739                        Cost newCost = costCalc( * srcIt++, * dstIt++, symtab, env );
     740                        if ( newCost == Cost::infinity ) {
     741                                return;
     742                        }
     743                        c += newCost;
     744                }
     745                if ( dstIt != dstEnd ) {
     746                        cost = Cost::infinity;
     747                } else {
     748                        cost = c;
     749                }
     750        }
     751}
     752
     753void ConversionCost_new::postvisit( const ast::VarArgsType * varArgsType ) {
     754        (void)varArgsType;
     755        if ( dynamic_cast< const ast::VarArgsType * >( dst ) ) {
     756                cost = Cost::zero;
     757        }
     758}
     759
     760void ConversionCost_new::postvisit( const ast::ZeroType * zeroType ) {
     761        (void)zeroType;
     762        if ( dynamic_cast< const ast::ZeroType * >( dst ) ) {
     763                cost = Cost::zero;
     764        } else if ( const ast::BasicType * dstAsBasic =
     765                        dynamic_cast< const ast::BasicType * >( dst ) ) {
     766                int tableResult = costMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ];
     767                if ( -1 == tableResult ) {
     768                        cost = Cost::unsafe;
     769                } else {
     770                        cost = Cost::zero;
     771                        cost.incSafe( tableResult + 1 );
     772                        cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
     773                }
     774        }
     775}
     776
     777void ConversionCost_new::postvisit( const ast::OneType * oneType ) {
     778        (void)oneType;
     779        if ( dynamic_cast< const ast::OneType * >( dst ) ) {
     780                cost = Cost::zero;
     781        } else if ( const ast::BasicType * dstAsBasic =
     782                        dynamic_cast< const ast::BasicType * >( dst ) ) {
     783                int tableResult = costMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ];
     784                if ( -1 == tableResult ) {
     785                        cost = Cost::unsafe;
     786                } else {
     787                        cost = Cost::zero;
     788                        cost.incSafe( tableResult + 1 );
     789                        cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
     790                }
     791        } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) {
     792                cost = Cost::zero;
     793                cost.incSafe( maxIntCost + 2 );
     794        }
     795}
     796
     797
    442798} // namespace ResolvExpr
    443799
  • src/ResolvExpr/ConversionCost.h

    r7951100 rb067d9b  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 09:37:28 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:38:24 2017
    13 // Update Count     : 4
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu Aug  8 16:13:00 2019
     13// Update Count     : 6
    1414//
    1515
     
    2020#include "Cost.h"             // for Cost
    2121
     22#include "AST/Fwd.hpp"
     23#include "AST/Pass.hpp"       // for WithShortCircuiting
    2224#include "Common/PassVisitor.h"
    2325#include "SynTree/Visitor.h"  // for Visitor
     
    3133        class TypeEnvironment;
    3234
    33         typedef std::function<Cost(Type *, Type *, const SymTab::Indexer &, const TypeEnvironment &)> CostFunction;
     35        typedef std::function<Cost(const Type *, const Type *, bool,
     36                const SymTab::Indexer &, const TypeEnvironment &)> CostFunction;
     37
    3438        struct ConversionCost : public WithShortCircuiting {
    3539          public:
    36                 ConversionCost( Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction );
     40                ConversionCost( const Type * dest, bool srcIsLvalue,
     41                        const SymTab::Indexer &indexer, const TypeEnvironment &env, CostFunction );
    3742
    3843                Cost get_cost() const { return cost; }
    3944
    40                 void previsit( BaseSyntaxNode * ) { visit_children = false; }
     45                void previsit( const BaseSyntaxNode * ) { visit_children = false; }
    4146
    42                 void postvisit( VoidType * voidType );
    43                 void postvisit( BasicType * basicType );
    44                 void postvisit( PointerType * pointerType );
    45                 void postvisit( ArrayType * arrayType );
    46                 void postvisit( ReferenceType * refType );
    47                 void postvisit( FunctionType * functionType );
    48                 void postvisit( StructInstType * aggregateUseType );
    49                 void postvisit( UnionInstType * aggregateUseType );
    50                 void postvisit( EnumInstType * aggregateUseType );
    51                 void postvisit( TraitInstType * aggregateUseType );
    52                 void postvisit( TypeInstType * aggregateUseType );
    53                 void postvisit( TupleType * tupleType );
    54                 void postvisit( VarArgsType * varArgsType );
    55                 void postvisit( ZeroType * zeroType );
    56                 void postvisit( OneType * oneType );
     47                void postvisit( const VoidType * voidType );
     48                void postvisit( const BasicType * basicType );
     49                void postvisit( const PointerType * pointerType );
     50                void postvisit( const ArrayType * arrayType );
     51                void postvisit( const ReferenceType * refType );
     52                void postvisit( const FunctionType * functionType );
     53                void postvisit( const StructInstType * aggregateUseType );
     54                void postvisit( const UnionInstType * aggregateUseType );
     55                void postvisit( const EnumInstType * aggregateUseType );
     56                void postvisit( const TraitInstType * aggregateUseType );
     57                void postvisit( const TypeInstType * aggregateUseType );
     58                void postvisit( const TupleType * tupleType );
     59                void postvisit( const VarArgsType * varArgsType );
     60                void postvisit( const ZeroType * zeroType );
     61                void postvisit( const OneType * oneType );
    5762          protected:
    58                 Type *dest;
     63                const Type * dest;
     64                bool srcIsLvalue;
    5965                const SymTab::Indexer &indexer;
    6066                Cost cost;
     
    6369        };
    6470
    65         typedef std::function<int(Type *, Type *, const SymTab::Indexer &, const TypeEnvironment &)> PtrsFunction;
    66         Cost convertToReferenceCost( Type * src, ReferenceType * dest, const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func );
     71        typedef std::function<int(const Type *, const Type *, const SymTab::Indexer &, const TypeEnvironment &)> PtrsFunction;
     72        Cost convertToReferenceCost( const Type * src, const ReferenceType * dest, bool srcIsLvalue,
     73                const SymTab::Indexer & indexer, const TypeEnvironment & env, PtrsFunction func );
     74
     75// Some function pointer types, differ in return type.
     76using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *,
     77        const ast::SymbolTable &, const ast::TypeEnvironment &)>;
     78using NumCostCalculation = std::function<int(const ast::Type *, const ast::Type *,
     79        const ast::SymbolTable &, const ast::TypeEnvironment &)>;
     80
     81#warning when the old ConversionCost is removed, get ride of the _new suffix.
     82class ConversionCost_new : public ast::WithShortCircuiting {
     83protected:
     84        const ast::Type * dst;
     85        const ast::SymbolTable & symtab;
     86        const ast::TypeEnvironment & env;
     87        CostCalculation costCalc;
     88public:
     89        Cost cost;
     90
     91        ConversionCost_new( const ast::Type * dst, const ast::SymbolTable & symtab,
     92                        const ast::TypeEnvironment & env, CostCalculation costCalc ) :
     93                dst( dst ), symtab( symtab ), env( env ), costCalc( costCalc ), cost( Cost::infinity )
     94        {}
     95
     96        void previsit( const ast::Node * ) { visit_children = false; }
     97
     98        void postvisit( const ast::VoidType * voidType );
     99        void postvisit( const ast::BasicType * basicType );
     100        void postvisit( const ast::PointerType * pointerType );
     101        void postvisit( const ast::ArrayType * arrayType );
     102        void postvisit( const ast::ReferenceType * refType );
     103        void postvisit( const ast::FunctionType * functionType );
     104        void postvisit( const ast::StructInstType * structInstType );
     105        void postvisit( const ast::UnionInstType * unionInstType );
     106        void postvisit( const ast::EnumInstType * enumInstType );
     107        void postvisit( const ast::TraitInstType * traitInstType );
     108        void postvisit( const ast::TypeInstType * typeInstType );
     109        void postvisit( const ast::TupleType * tupleType );
     110        void postvisit( const ast::VarArgsType * varArgsType );
     111        void postvisit( const ast::ZeroType * zeroType );
     112        void postvisit( const ast::OneType * oneType );
     113};
     114
     115Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dest,
     116        const ast::SymbolTable & indexer, const ast::TypeEnvironment & env, NumCostCalculation func );
     117
    67118} // namespace ResolvExpr
    68119
  • src/ResolvExpr/Cost.h

    r7951100 rb067d9b  
    77// Cost.h --
    88//
    9 // Author           : Richard C. Bilson
     9// Author           : Peter Buhr and Aaron Moss
    1010// Created On       : Sun May 17 09:39:50 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:35:55 2017
    13 // Update Count     : 5
     12// Last Modified On : Fri Jun 21 11:39:13 2019
     13// Update Count     : 63
    1414//
    1515
     
    1717
    1818#include <iostream>
     19#include <cassert>
     20#include <climits>
    1921
    2022namespace ResolvExpr {
     23        // To maximize performance and space, the 7 resolution costs are packed into a single 64-bit word. However, the
     24        // specialization cost is a negative value so a correction is needed is a few places.
     25
    2126        class Cost {
    22           private:
    23                 Cost( int unsafeCost, int polyCost, int safeCost, int referenceCost );
     27                union {
     28                        struct {
     29                        #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
     30                                // Little-endian => first value is low priority and last is high priority.
     31                                unsigned char padding;                                  ///< unused
     32                                unsigned char referenceCost;                    ///< reference conversions
     33                                unsigned char specCost;                                 ///< Polymorphic type specializations (type assertions), negative cost
     34                                unsigned char varCost;                                  ///< Count of polymorphic type variables
     35                                unsigned char signCost;                                 ///< Count of safe sign conversions
     36                                unsigned char safeCost;                                 ///< Safe (widening) conversions
     37                                unsigned char polyCost;                                 ///< Count of parameters and return values bound to some poly type
     38                                unsigned char unsafeCost;                               ///< Unsafe (narrowing) conversions
     39                        #else
     40                                #error Cost BIG_ENDIAN unsupported
     41                        #endif
     42                        } v;
     43                        uint64_t all;
     44                };
     45                static const unsigned char correctb = 0xff;             // byte correction for negative spec cost
     46                static const uint64_t correctw = 0x00'00'00'00'00'ff'00'00; //' word correction for negative spec cost
     47          public:
     48                // Compiler adjusts constants for correct endian.
     49                enum : uint64_t {
     50                        zero      = 0x00'00'00'00'00'ff'00'00,
     51                        infinity  = 0xff'ff'ff'ff'ff'00'ff'ff,
     52                        unsafe    = 0x01'00'00'00'00'ff'00'00,
     53                        poly      = 0x00'01'00'00'00'ff'00'00,
     54                        safe      = 0x00'00'01'00'00'ff'00'00,
     55                        sign      = 0x00'00'00'01'00'ff'00'00,
     56                        var       = 0x00'00'00'00'01'ff'00'00,
     57                        spec      = 0x00'00'00'00'00'fe'00'00,
     58                        reference = 0x00'00'00'00'00'ff'01'00,
     59                }; //'
    2460
    25           public:
    26                 Cost & incUnsafe( int inc = 1 );
    27                 Cost & incPoly( int inc = 1 );
    28                 Cost & incSafe( int inc = 1 );
    29                 Cost & incReference( int inc = 1 );
     61                Cost( uint64_t all ) { Cost::all = all; }
     62                Cost( int unsafeCost, int polyCost, int safeCost, int signCost, int varCost, int specCost, int referenceCost ) {
     63                        // Assume little-endian => first value is low priority and last is high priority.
     64                        v = {
     65                        #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
     66                                (unsigned char)0,                                               // padding
     67                                (unsigned char)referenceCost,                   // low priority
     68                                (unsigned char)(specCost + correctb),   // correct for signedness
     69                                (unsigned char)varCost,
     70                                (unsigned char)signCost,
     71                                (unsigned char)safeCost,
     72                                (unsigned char)polyCost,
     73                                (unsigned char)unsafeCost,                              // high priority
     74                        #else
     75                                #error Cost BIG_ENDIAN unsupported
     76                        #endif
     77                        };
     78                }
    3079
    31                 int get_unsafeCost() const { return unsafeCost; }
    32                 int get_polyCost() const { return polyCost; }
    33                 int get_safeCost() const { return safeCost; }
    34                 int get_referenceCost() const { return referenceCost; }
     80                int get_unsafeCost() const { return v.unsafeCost; }
     81                int get_polyCost() const { return v.polyCost; }
     82                int get_safeCost() const { return v.safeCost; }
     83                int get_signCost() const { return v.signCost; }
     84                int get_varCost() const { return v.varCost; }
     85                int get_specCost() const { return -(correctb - v.specCost); }
     86                int get_referenceCost() const { return v.referenceCost; }
    3587
    36                 Cost operator+( const Cost &other ) const;
    37                 Cost operator-( const Cost &other ) const;
    38                 Cost &operator+=( const Cost &other );
    39                 bool operator<( const Cost &other ) const;
    40                 bool operator==( const Cost &other ) const;
    41                 bool operator!=( const Cost &other ) const;
    42                 friend std::ostream &operator<<( std::ostream &os, const Cost &cost );
     88                friend bool operator==( const Cost, const Cost );
     89                friend bool operator!=( const Cost lhs, const Cost rhs );
     90                // returns negative for *this < rhs, 0 for *this == rhs, positive for *this > rhs
     91                int compare( const Cost rhs ) const {
     92                        if ( all == infinity ) return 1;
     93                        if ( rhs.all == infinity ) return -1;
     94                        return all > rhs.all ? 1 : all == rhs.all ? 0 : -1;
     95                }
     96                friend bool operator<( const Cost lhs, const Cost rhs );
    4397
    44                 static const Cost zero;
    45                 static const Cost infinity;
     98                friend Cost operator+( const Cost lhs, const Cost rhs );
     99 
     100                Cost operator+=( const Cost rhs ) {
     101                        if ( all == infinity ) return *this;
     102                        if ( rhs.all == infinity ) {
     103                                all = infinity;
     104                                return *this;
     105                        }
     106                        all += rhs.all - correctw;                                      // correct for negative spec cost
     107                        return *this;
     108                }
    46109
    47                 static const Cost unsafe;
    48                 static const Cost poly;
    49                 static const Cost safe;
    50                 static const Cost reference;
    51           private:
    52                 int compare( const Cost &other ) const;
     110                Cost incUnsafe( int inc = 1 ) {
     111                        if ( all != infinity ) { assert( v.unsafeCost + inc <= UCHAR_MAX ); v.unsafeCost += inc; }
     112                        return *this;
     113                }
    53114
    54                 int unsafeCost;
    55                 int polyCost;
    56                 int safeCost;
    57                 int referenceCost;
     115                Cost incPoly( int inc = 1 ) {
     116                        if ( all != infinity ) { assert( v.polyCost + inc <= UCHAR_MAX ); v.polyCost += inc; }
     117                        return *this;
     118                }
     119
     120                Cost incSafe( int inc = 1 ) {
     121                        if ( all != infinity ) { assert( v.safeCost + inc <= UCHAR_MAX ); v.safeCost += inc; }
     122                        return *this;
     123                }
     124
     125                Cost incSign( int inc = 1 ) {
     126                        if ( all != infinity ) { assert( v.signCost + inc <= UCHAR_MAX ); v.signCost += inc; }
     127                        return *this;
     128                }
     129
     130                Cost incVar( int inc = 1 ) {
     131                        if ( all != infinity ) { assert( v.varCost + inc <= UCHAR_MAX ); v.varCost += inc; }
     132                        return *this;
     133                }
     134
     135                Cost decSpec( int dec = 1 ) {
     136                        if ( all != infinity ) { assert( v.specCost - dec >= 0 ); v.specCost -= dec; }
     137                        return *this;
     138                }
     139
     140                Cost incReference( int inc = 1 ) {
     141                        if ( all != infinity ) { assert( v.referenceCost + inc <= UCHAR_MAX ); v.referenceCost += inc; }
     142                        return *this;
     143                }
     144
     145                friend std::ostream & operator<<( std::ostream & os, const Cost cost );
    58146        };
    59147
    60         inline Cost::Cost( int unsafeCost, int polyCost, int safeCost, int referenceCost ) : unsafeCost( unsafeCost ), polyCost( polyCost ), safeCost( safeCost ), referenceCost( referenceCost ) {}
    61 
    62         inline Cost & Cost::incUnsafe( int inc ) {
    63                 if ( *this == infinity ) return *this;
    64                 unsafeCost += inc;
    65                 return *this;
     148        inline bool operator==( const Cost lhs, const Cost rhs ) {
     149                return lhs.all == rhs.all;
    66150        }
    67151
    68         inline Cost & Cost::incPoly( int inc ) {
    69                 if ( *this == infinity ) return *this;
    70                 polyCost += inc;
    71                 return *this;
     152        inline bool operator!=( const Cost lhs, const Cost rhs ) {
     153                return !( lhs.all == rhs.all );
    72154        }
    73155
    74         inline Cost & Cost::incSafe( int inc ) {
    75                 if ( *this == infinity ) return *this;
    76                 safeCost += inc;
    77                 return *this;
     156        inline bool operator<( const Cost lhs, const Cost rhs ) {
     157                if ( lhs.all == Cost::infinity ) return false;
     158                if ( rhs.all == Cost::infinity ) return true;
     159                return lhs.all < rhs.all;
    78160        }
    79161
    80         inline Cost & Cost::incReference( int inc ) {
    81                 if ( *this == infinity ) return *this;
    82                 referenceCost += inc;
    83                 return *this;
     162        inline Cost operator+( const Cost lhs, const Cost rhs ) {
     163                if ( lhs.all == Cost::infinity || rhs.all == Cost::infinity ) return Cost{ Cost::infinity };
     164                return Cost{ lhs.all + rhs.all - Cost::correctw }; // correct for negative spec cost
    84165        }
    85166
    86         inline Cost Cost::operator+( const Cost &other ) const {
    87                 if ( *this == infinity || other == infinity ) return infinity;
    88                 return Cost( unsafeCost + other.unsafeCost, polyCost + other.polyCost, safeCost + other.safeCost, referenceCost + other.referenceCost );
    89         }
    90 
    91         inline Cost Cost::operator-( const Cost &other ) const {
    92                 if ( *this == infinity || other == infinity ) return infinity;
    93                 return Cost( unsafeCost - other.unsafeCost, polyCost - other.polyCost, safeCost - other.safeCost, referenceCost - other.referenceCost );
    94         }
    95 
    96         inline Cost &Cost::operator+=( const Cost &other ) {
    97                 if ( *this == infinity ) return *this;
    98                 if ( other == infinity ) {
    99                         *this = infinity;
    100                         return *this;
    101                 }
    102                 unsafeCost += other.unsafeCost;
    103                 polyCost += other.polyCost;
    104                 safeCost += other.safeCost;
    105                 referenceCost += other.referenceCost;
    106                 return *this;
    107         }
    108 
    109         inline bool Cost::operator<( const Cost &other ) const {
    110                 if ( *this == infinity ) return false;
    111                 if ( other == infinity ) return true;
    112 
    113                 if ( unsafeCost > other.unsafeCost ) {
    114                         return false;
    115                 } else if ( unsafeCost < other.unsafeCost ) {
    116                         return true;
    117                 } else if ( polyCost > other.polyCost ) {
    118                         return false;
    119                 } else if ( polyCost < other.polyCost ) {
    120                         return true;
    121                 } else if ( safeCost > other.safeCost ) {
    122                         return false;
    123                 } else if ( safeCost < other.safeCost ) {
    124                         return true;
    125                 } else if ( referenceCost > other.referenceCost ) {
    126                         return false;
    127                 } else if ( referenceCost < other.referenceCost ) {
    128                         return true;
    129                 } else {
    130                         return false;
    131                 } // if
    132         }
    133 
    134         inline bool Cost::operator==( const Cost &other ) const {
    135                 return unsafeCost == other.unsafeCost
    136                         && polyCost == other.polyCost
    137                         && safeCost == other.safeCost
    138                         && referenceCost == other.referenceCost;
    139         }
    140 
    141         inline bool Cost::operator!=( const Cost &other ) const {
    142                 return !( *this == other );
    143         }
    144 
    145         inline std::ostream &operator<<( std::ostream &os, const Cost &cost ) {
    146                 os << "( " << cost.unsafeCost << ", " << cost.polyCost << ", " << cost.safeCost << ", " << cost.referenceCost << " )";
    147                 return os;
     167        inline std::ostream & operator<<( std::ostream & os, const Cost cost ) {
     168                return os << "( " << cost.get_unsafeCost() << ", " << cost.get_polyCost() << ", " << cost.get_safeCost()
     169                                  << ", " << cost.get_signCost() << ", " << cost.get_varCost() << ", " << cost.get_specCost()
     170                                  << ", " << cost.get_referenceCost() << " )";
    148171        }
    149172} // namespace ResolvExpr
  • src/ResolvExpr/CurrentObject.cc

    r7951100 rb067d9b  
    1616#include <stddef.h>                    // for size_t
    1717#include <cassert>                     // for assertf, assert, safe_dynamic_...
     18#include <deque>
    1819#include <iostream>                    // for ostream, operator<<, basic_ost...
    1920#include <stack>                       // for stack
    2021#include <string>                      // for string, operator<<, allocator
    2122
     23#include "AST/Expr.hpp"                // for InitAlternative
     24#include "AST/GenericSubstitution.hpp" // for genericSubstitution
     25#include "AST/Init.hpp"                // for Designation
     26#include "AST/Node.hpp"                // for readonly
     27#include "AST/Type.hpp"
    2228#include "Common/Indenter.h"           // for Indenter, operator<<
    2329#include "Common/SemanticError.h"      // for SemanticError
     
    139145                ArrayIterator( ArrayType * at ) : array( at ) {
    140146                        PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
    141                         base = at->get_base();
     147                        base = at->base;
    142148                        memberIter = createMemberIterator( base );
    143                         if ( at->isVarLen ) SemanticError( at, "VLA initialization does not support @=" );
    144                         setSize( at->get_dimension() );
     149                        if ( at->isVarLen ) SemanticError( at, "VLA initialization does not support @=: " );
     150                        setSize( at->dimension );
    145151                }
    146152
     
    150156
    151157        private:
    152                 void setSize( Expression * expr ) {
    153                         if ( ConstantExpr * constExpr = dynamic_cast< ConstantExpr * >( expr ) ) {
    154                                 try {
    155                                         size = constExpr->intValue();
    156                                         PRINT( std::cerr << "array type with size: " << size << std::endl; )
    157                                 } catch ( SemanticErrorException & ) {
    158                                         SemanticError( expr, "Constant expression of non-integral type in array dimension: " );
    159                                 }
    160                         }       else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
    161                                 setSize( castExpr->get_arg() ); // xxx - need to perform the conversion specified by the cast
    162                         } else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) {
    163                                 if ( EnumInstType * inst = dynamic_cast< EnumInstType * > ( varExpr->result ) ) {
    164                                         long long int value;
    165                                         if ( inst->baseEnum->valueOf( varExpr->var, value ) ) {
    166                                                 size = value;
    167                                         }
    168                                 }
     158                void setSize( Expression * expr ) { // replace this logic with an eval call
     159                        auto res = eval(expr);
     160                        if (res.second) {
     161                                size = res.first;
    169162                        } else {
    170                                 assertf( false, "unhandled expression in setSize: %s", toString( expr ).c_str() ); // xxx - if not a constant expression, it's not simple to determine how long the array actually is, which is necessary for initialization to be done correctly -- fix this
     163                                SemanticError( expr->location, toString("Array designator must be a constant expression: ", expr) );
    171164                        }
    172165                }
     
    592585} // namespace ResolvExpr
    593586
     587namespace ast {
     588        /// create a new MemberIterator that traverses a type correctly
     589        MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type );
     590
     591        /// Iterates "other" types (e.g. basic, pointer) which do not change at list initializer entry
     592        class SimpleIterator final : public MemberIterator {
     593                CodeLocation location;
     594                readonly< Type > type = nullptr;
     595        public:
     596                SimpleIterator( const CodeLocation & loc, const Type * t ) : location( loc ), type( t ) {}
     597
     598                void setPosition(
     599                        std::deque< ptr< Expr > >::const_iterator begin,
     600                        std::deque< ptr< Expr > >::const_iterator end
     601                ) override {
     602                        if ( begin != end ) {
     603                                SemanticError( location, "Un-designated initializer given non-empty designator" );
     604                        }
     605                }
     606
     607                std::deque< InitAlternative > operator* () const override { return first(); }
     608
     609                operator bool() const override { return type; }
     610
     611                SimpleIterator & bigStep() override { return smallStep(); }
     612                SimpleIterator & smallStep() override {
     613                        type = nullptr;  // empty on increment because no members
     614                        return *this;
     615                }
     616
     617                const Type * getType() override { return type; }
     618
     619                const Type * getNext() override { return type; }
     620
     621                std::deque< InitAlternative > first() const override {
     622                        if ( type ) return { InitAlternative{ type, new Designation{ location } } };
     623                        return {};
     624                }
     625        };
     626
     627        /// Iterates array types
     628        class ArrayIterator final : public MemberIterator {
     629                CodeLocation location;
     630                readonly< ArrayType > array = nullptr;
     631                readonly< Type > base = nullptr;
     632                size_t index = 0;
     633                size_t size = 0;
     634                std::unique_ptr< MemberIterator > memberIter;
     635
     636                void setSize( const Expr * expr ) {
     637                        auto res = eval(expr);
     638                        if ( ! res.second ) {
     639                                SemanticError( location,
     640                                        toString("Array designator must be a constant expression: ", expr ) );
     641                        }
     642                        size = res.first;
     643                }
     644
     645        public:
     646                ArrayIterator( const CodeLocation & loc, const ArrayType * at )
     647                : location( loc ), array( at ), base( at->base ) {
     648                        PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
     649                        memberIter.reset( createMemberIterator( loc, base ) );
     650                        if ( at->isVarLen ) {
     651                                SemanticError( location, at, "VLA initialization does not support @=: " );
     652                        }
     653                        setSize( at->dimension );
     654                }
     655
     656                void setPosition( const Expr * expr ) {
     657                        // need to permit integer-constant-expressions, including: integer constants,
     658                        // enumeration constants, character constants, sizeof expressions, alignof expressions,
     659                        // cast expressions
     660                        if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) {
     661                                try {
     662                                        index = constExpr->intValue();
     663                                } catch ( SemanticErrorException & ) {
     664                                        SemanticError( expr,
     665                                                "Constant expression of non-integral type in array designator: " );
     666                                }
     667                        } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) {
     668                                setPosition( castExpr->arg );
     669                        } else if (
     670                                dynamic_cast< const SizeofExpr * >( expr )
     671                                || dynamic_cast< const AlignofExpr * >( expr )
     672                        ) {
     673                                index = 0;
     674                        } else {
     675                                assertf( false,
     676                                        "bad designator given to ArrayIterator: %s", toString( expr ).c_str() );
     677                        }
     678                }
     679
     680                void setPosition(
     681                        std::deque< ptr< Expr > >::const_iterator begin,
     682                        std::deque< ptr< Expr > >::const_iterator end
     683                ) override {
     684                        if ( begin == end ) return;
     685
     686                        setPosition( *begin );
     687                        memberIter->setPosition( ++begin, end );
     688                }
     689
     690                std::deque< InitAlternative > operator* () const override { return first(); }
     691
     692                operator bool() const override { return index < size; }
     693
     694                ArrayIterator & bigStep() override {
     695                        PRINT( std::cerr << "bigStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
     696                        ++index;
     697                        memberIter.reset( index < size ? createMemberIterator( location, base ) : nullptr );
     698                        return *this;
     699                }
     700
     701                ArrayIterator & smallStep() override {
     702                        PRINT( std::cerr << "smallStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
     703                        if ( memberIter ) {
     704                                PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; )
     705                                memberIter->smallStep();
     706                                if ( *memberIter ) {
     707                                        PRINT( std::cerr << "has valid member iter" << std::endl; )
     708                                        return *this;
     709                                }
     710                        }
     711                        return bigStep();
     712                }
     713
     714                const Type * getType() override { return array; }
     715
     716                const Type * getNext() override { return base; }
     717
     718                std::deque< InitAlternative > first() const override {
     719                        PRINT( std::cerr << "first in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
     720                        if ( memberIter && *memberIter ) {
     721                                std::deque< InitAlternative > ret = memberIter->first();
     722                                for ( InitAlternative & alt : ret ) {
     723                                        alt.designation.get_and_mutate()->designators.emplace_front(
     724                                                ConstantExpr::from_ulong( location, index ) );
     725                                }
     726                                return ret;
     727                        }
     728                        return {};
     729                }
     730        };
     731
     732        class AggregateIterator : public MemberIterator {
     733        protected:
     734                using MemberList = std::vector< ptr< Decl > >;
     735
     736                CodeLocation location;
     737                std::string kind;  // for debug
     738                std::string name;
     739                const Type * inst;
     740                const MemberList & members;
     741                MemberList::const_iterator curMember;
     742                bool atbegin = true;  // false at first {small,big}Step
     743                const Type * curType = nullptr;
     744                std::unique_ptr< MemberIterator > memberIter = nullptr;
     745                TypeSubstitution sub;
     746
     747                bool init() {
     748                        PRINT( std::cerr << "--init()--" << members.size() << std::endl; )
     749                        if ( curMember != members.end() ) {
     750                                if ( auto field = curMember->as< ObjectDecl >() ) {
     751                                        PRINT( std::cerr << "incremented to field: " << field << std::endl; )
     752                                        curType = field->get_type();
     753                                        memberIter.reset( createMemberIterator( location, curType ) );
     754                                        return true;
     755                                }
     756                        }
     757                        return false;
     758                }
     759
     760                AggregateIterator(
     761                        const CodeLocation & loc, const std::string k, const std::string & n, const Type * i,
     762                        const MemberList & ms )
     763                : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ),
     764                  sub( genericSubstitution( i ) ) {
     765                        PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; )
     766                        init();
     767                }
     768
     769        public:
     770                void setPosition(
     771                        std::deque< ptr< Expr > >::const_iterator begin,
     772                        std::deque< ptr< Expr > >::const_iterator end
     773                ) final {
     774                        if ( begin == end ) return;
     775
     776                        if ( auto varExpr = begin->as< VariableExpr >() ) {
     777                                for ( curMember = members.begin(); curMember != members.end(); ++curMember ) {
     778                                        if ( *curMember != varExpr->var ) continue;
     779
     780                                        ++begin;
     781
     782                                        memberIter.reset( createMemberIterator( location, varExpr->result ) );
     783                                        curType = varExpr->result;
     784                                        atbegin = curMember == members.begin() && begin == end;
     785                                        memberIter->setPosition( begin, end );
     786                                        return;
     787                                }
     788                                assertf( false,
     789                                        "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() );
     790                        } else {
     791                                assertf( false,
     792                                        "bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() );
     793                        }
     794                }
     795
     796                std::deque< InitAlternative > operator* () const final {
     797                        if ( memberIter && *memberIter ) {
     798                                std::deque< InitAlternative > ret = memberIter->first();
     799                                PRINT( std::cerr << "sub: " << sub << std::endl; )
     800                                for ( InitAlternative & alt : ret ) {
     801                                        PRINT( std::cerr << "iterating and adding designators" << std::endl; )
     802                                        alt.designation.get_and_mutate()->designators.emplace_front(
     803                                                new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
     804                                        // need to substitute for generic types so that casts are to concrete types
     805                                        PRINT( std::cerr << "  type is: " << alt.type; )
     806                                        sub.apply( alt.type ); // also apply to designation??
     807                                        PRINT( std::cerr << " ==> " << alt.type << std::endl; )
     808                                }
     809                                return ret;
     810                        }
     811                        return {};
     812                }
     813
     814                AggregateIterator & smallStep() final {
     815                        PRINT( std::cerr << "smallStep in " << kind << std::endl; )
     816                        atbegin = false;
     817                        if ( memberIter ) {
     818                                PRINT( std::cerr << "has member iter, incrementing..." << std::endl; )
     819                                memberIter->smallStep();
     820                                if ( *memberIter ) {
     821                                        PRINT( std::cerr << "success!" << std::endl; )
     822                                        return *this;
     823                                }
     824                        }
     825                        return bigStep();
     826                }
     827
     828                AggregateIterator & bigStep() override = 0;
     829
     830                const Type * getType() final { return inst; }
     831
     832                const Type * getNext() final {
     833                        return ( memberIter && *memberIter ) ? memberIter->getType() : nullptr;
     834                }
     835
     836                std::deque< InitAlternative > first() const final {
     837                        std::deque< InitAlternative > ret;
     838                        PRINT( std::cerr << "first " << kind << std::endl; )
     839                        if ( memberIter && *memberIter ) {
     840                                PRINT( std::cerr << "adding children" << std::endl; )
     841                                ret = memberIter->first();
     842                                for ( InitAlternative & alt : ret ) {
     843                                        PRINT( std::cerr << "iterating and adding designators" << std::endl; )
     844                                        alt.designation.get_and_mutate()->designators.emplace_front(
     845                                                new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
     846                                }
     847                        }
     848                        if ( atbegin ) {
     849                                // only add self if at the very beginning of the structure
     850                                PRINT( std::cerr << "adding self" << std::endl; )
     851                                ret.emplace_front( inst, new Designation{ location } );
     852                        }
     853                        return ret;
     854                }
     855        };
     856
     857        class StructIterator final : public AggregateIterator {
     858        public:
     859                StructIterator( const CodeLocation & loc, const StructInstType * inst )
     860                : AggregateIterator( loc, "StructIterator", inst->name, inst, inst->base->members ) {}
     861
     862                operator bool() const override {
     863                        return curMember != members.end() || (memberIter && *memberIter);
     864                }
     865
     866                StructIterator & bigStep() override {
     867                        PRINT( std::cerr << "bigStep in " << kind << std::endl; )
     868                        atbegin = false;
     869                        memberIter = nullptr;
     870                        curType = nullptr;
     871                        while ( curMember != members.end() ) {
     872                                ++curMember;
     873                                if ( init() ) return *this;
     874                        }
     875                        return *this;
     876                }
     877        };
     878
     879        class UnionIterator final : public AggregateIterator {
     880        public:
     881                UnionIterator( const CodeLocation & loc, const UnionInstType * inst )
     882                : AggregateIterator( loc, "UnionIterator", inst->name, inst, inst->base->members ) {}
     883
     884                operator bool() const override { return memberIter && *memberIter; }
     885
     886                UnionIterator & bigStep() override {
     887                        // unions only initialize one member
     888                        PRINT( std::cerr << "bigStep in " << kind << std::endl; )
     889                        atbegin = false;
     890                        memberIter = nullptr;
     891                        curType = nullptr;
     892                        curMember = members.end();
     893                        return *this;
     894                }
     895        };
     896
     897        class TupleIterator final : public AggregateIterator {
     898        public:
     899                TupleIterator( const CodeLocation & loc, const TupleType * inst )
     900                : AggregateIterator(
     901                        loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members
     902                ) {}
     903
     904                operator bool() const override {
     905                        return curMember != members.end() || (memberIter && *memberIter);
     906                }
     907
     908                TupleIterator & bigStep() override {
     909                        PRINT( std::cerr << "bigStep in " << kind << std::endl; )
     910                        atbegin = false;
     911                        memberIter = nullptr;
     912                        curType = nullptr;
     913                        while ( curMember != members.end() ) {
     914                                ++curMember;
     915                                if ( init() ) return *this;
     916                        }
     917                        return *this;
     918                }
     919        };
     920
     921        MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type ) {
     922                if ( auto aggr = dynamic_cast< const ReferenceToType * >( type ) ) {
     923                        if ( auto sit = dynamic_cast< const StructInstType * >( aggr ) ) {
     924                                return new StructIterator{ loc, sit };
     925                        } else if ( auto uit = dynamic_cast< const UnionInstType * >( aggr ) ) {
     926                                return new UnionIterator{ loc, uit };
     927                        } else {
     928                                assertf(
     929                                        dynamic_cast< const EnumInstType * >( aggr )
     930                                                || dynamic_cast< const TypeInstType * >( aggr ),
     931                                        "Encountered unhandled ReferenceToType in createMemberIterator: %s",
     932                                                toString( type ).c_str() );
     933                                return new SimpleIterator{ loc, type };
     934                        }
     935                } else if ( auto at = dynamic_cast< const ArrayType * >( type ) ) {
     936                        return new ArrayIterator{ loc, at };
     937                } else if ( auto tt = dynamic_cast< const TupleType * >( type ) ) {
     938                        return new TupleIterator{ loc, tt };
     939                } else {
     940                        return new SimpleIterator{ loc, type };
     941                }
     942        }
     943
     944        CurrentObject::CurrentObject( const CodeLocation & loc, const Type * type ) : objStack() {
     945                objStack.emplace_back( new SimpleIterator{ loc, type } );
     946        }
     947
     948        const Designation * CurrentObject::findNext( const Designation * designation ) {
     949                using DesignatorChain = std::deque< ptr< Expr > >;
     950                PRINT( std::cerr << "___findNext" << std::endl; )
     951               
     952                // find all the d's
     953                std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts;
     954                std::deque< const Type * > curTypes{ objStack.back()->getType() }, newTypes;
     955                for ( const Expr * expr : designation->designators ) {
     956                        PRINT( std::cerr << "____untyped: " << expr << std::endl; )
     957                        auto dit = desigAlts.begin();
     958                        if ( auto nexpr = dynamic_cast< const NameExpr * >( expr ) ) {
     959                                for ( const Type * t : curTypes ) {
     960                                        assert( dit != desigAlts.end() );
     961
     962                                        DesignatorChain & d = *dit;
     963                                        PRINT( std::cerr << "____actual: " << t << std::endl; )
     964                                        if ( auto refType = dynamic_cast< const ReferenceToType * >( t ) ) {
     965                                                // concatenate identical field names
     966                                                for ( const Decl * mem : refType->lookup( nexpr->name ) ) {
     967                                                        if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) {
     968                                                                PRINT( std::cerr << "____alt: " << field->type << std::endl; )
     969                                                                DesignatorChain d2 = d;
     970                                                                d2.emplace_back( new VariableExpr{ expr->location, field } );
     971                                                                newDesigAlts.emplace_back( std::move( d2 ) );
     972                                                                newTypes.emplace_back( field->type );
     973                                                        }
     974                                                }
     975                                        }
     976
     977                                        ++dit;
     978                                }
     979                        } else {
     980                                for ( const Type * t : curTypes ) {
     981                                        assert( dit != desigAlts.end() );
     982
     983                                        DesignatorChain & d = *dit;
     984                                        if ( auto at = dynamic_cast< const ArrayType * >( t ) ) {
     985                                                PRINT( std::cerr << "____alt: " << at->get_base() << std::endl; )
     986                                                d.emplace_back( expr );
     987                                                newDesigAlts.emplace_back( d );
     988                                                newTypes.emplace_back( at->base );
     989                                        }
     990                                }
     991                        }
     992
     993                        // reset queue
     994                        desigAlts = std::move( newDesigAlts );
     995                        newDesigAlts.clear();
     996                        curTypes = std::move( newTypes );
     997                        newTypes.clear();
     998                        assertf( desigAlts.size() == curTypes.size(), "Designator alternatives (%zu) and current types (%zu) out of sync", desigAlts.size(), curTypes.size() );
     999                }
     1000
     1001                if ( desigAlts.size() > 1 ) {
     1002                        SemanticError( designation, toString("Too many alternatives (", desigAlts.size(), ") for designation: ") );
     1003                } else if ( desigAlts.empty() ) {
     1004                        SemanticError( designation, "No reasonable alternatives for designation: " );
     1005                }
     1006
     1007                DesignatorChain & d = desigAlts.back();
     1008                PRINT( for ( Expression * expr : d ) {
     1009                        std::cerr << "____desig: " << expr << std::endl;
     1010                } ) // for
     1011                assertf( ! curTypes.empty(), "empty designator chosen");
     1012
     1013                // set new designators
     1014                assertf( ! objStack.empty(), "empty object stack when setting designation" );
     1015                Designation * actualDesignation =
     1016                        new Designation{ designation->location, DesignatorChain{d} };
     1017                objStack.back()->setPosition( d ); // destroys d
     1018                return actualDesignation;
     1019        }
     1020
     1021        void CurrentObject::setNext( const Designation * designation ) {
     1022                PRINT( std::cerr << "____setNext" << designation << std::endl; )
     1023                assertf( ! objStack.empty(), "obj stack empty in setNext" );
     1024                objStack.back()->setPosition( designation->designators );
     1025        }
     1026
     1027        void CurrentObject::increment() {
     1028                PRINT( std::cerr << "____increment" << std::endl; )
     1029                if ( objStack.empty() ) return;
     1030                PRINT( std::cerr << *objStack.back() << std::endl; )
     1031                objStack.back()->smallStep();
     1032        }
     1033
     1034        void CurrentObject::enterListInit( const CodeLocation & loc ) {
     1035                PRINT( std::cerr << "____entering list init" << std::endl; )
     1036                assertf( ! objStack.empty(), "empty obj stack entering list init" );
     1037                const ast::Type * type = objStack.back()->getNext();
     1038                assert( type );
     1039                objStack.emplace_back( createMemberIterator( loc, type ) );
     1040        }
     1041
     1042        void CurrentObject::exitListInit() {
     1043                PRINT( std::cerr << "____exiting list init" << std::endl; )
     1044                assertf( ! objStack.empty(), "objstack empty" );
     1045                objStack.pop_back();
     1046                if ( ! objStack.empty() ) {
     1047                        PRINT( std::cerr << *objStack.back() << std::endl; )
     1048                        objStack.back()->bigStep();
     1049                }
     1050        }
     1051
     1052        std::deque< InitAlternative > CurrentObject::getOptions() {
     1053                PRINT( std::cerr << "____getting current options" << std::endl; )
     1054                assertf( ! objStack.empty(), "objstack empty in getOptions" );
     1055                return **objStack.back();
     1056        }
     1057
     1058        const Type * CurrentObject::getCurrentType() {
     1059                PRINT( std::cerr << "____getting current type" << std::endl; )
     1060                assertf( ! objStack.empty(), "objstack empty in getCurrentType" );
     1061                return objStack.back()->getNext();
     1062        }
     1063}
     1064
    5941065// Local Variables: //
    5951066// tab-width: 4 //
  • src/ResolvExpr/CurrentObject.h

    r7951100 rb067d9b  
    1616#pragma once
    1717
     18#include <deque>
    1819#include <list>   // for list
     20#include <memory> // for unique_ptr
    1921#include <stack>  // for stack
     22#include <vector>
     23
     24#include "AST/Node.hpp"  // for ptr
     25#include "Common/CodeLocation.h"
    2026
    2127class Designation;
     
    5258} // namespace ResolvExpr
    5359
     60namespace ast {
     61        // AST class types
     62        class Designation;
     63        struct InitAlternative;
     64        class Type;
     65
     66        /// Iterates members of a type by initializer
     67        class MemberIterator {
     68        public:
     69                virtual ~MemberIterator() {}
     70
     71                /// Internal set position based on iterator ranges
     72                virtual void setPosition(
     73                        std::deque< ptr< Expr > >::const_iterator it,
     74                        std::deque< ptr< Expr > >::const_iterator end ) = 0;
     75
     76                /// walks the current object using the given designators as a guide
     77                void setPosition( const std::deque< ptr< Expr > > & designators ) {
     78                        setPosition( designators.begin(), designators.end() );
     79                }
     80
     81                /// retrieve the list of possible (Type,Designation) pairs for the current position in the
     82                /// current object
     83                virtual std::deque< InitAlternative > operator* () const = 0;
     84
     85                /// true if the iterator is not currently at the end
     86                virtual operator bool() const = 0;
     87
     88                /// moves the iterator by one member in the current object
     89                virtual MemberIterator & bigStep() = 0;
     90
     91                /// moves the iterator by one member in the current subobject
     92                virtual MemberIterator & smallStep() = 0;
     93
     94                /// the type of the current object
     95                virtual const Type * getType() = 0;
     96
     97                /// the type of the current subobject
     98                virtual const Type * getNext() = 0;
     99       
     100                /// helper for operator*; aggregates must add designator to each init alternative, but
     101                /// adding designators in operator* creates duplicates
     102                virtual std::deque< InitAlternative > first() const = 0;
     103        };
     104
     105        /// Builds initializer lists in resolution
     106        class CurrentObject final {
     107                std::vector< std::shared_ptr<MemberIterator> > objStack;
     108       
     109        public:
     110                CurrentObject() = default;
     111                CurrentObject( const CodeLocation & loc, const Type * type );
     112
     113                /// resolves unresolved designation
     114                const Designation * findNext( const Designation * designation );
     115                /// sets current position using the resolved designation
     116                void setNext( const ast::Designation * designation );
     117                /// steps to next sub-object of current object
     118                void increment();
     119                /// sets new current object for the duration of this brace-enclosed intializer-list
     120                void enterListInit( const CodeLocation & loc );
     121                /// restores previous current object
     122                void exitListInit();
     123                /// produces a list of alternatives (Type *, Designation *) for the current sub-object's
     124                /// initializer.
     125                std::deque< InitAlternative > getOptions();
     126                /// produces the type of the current object but no subobjects
     127                const Type * getCurrentType();
     128        };
     129} // namespace ast
     130
    54131// Local Variables: //
    55132// tab-width: 4 //
  • src/ResolvExpr/ExplodedActual.cc

    r7951100 rb067d9b  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // Alternative.h --
     7// ExplodedActual.cc --
    88//
    99// Author           : Aaron B. Moss
     
    2424        }
    2525}
     26
     27// Local Variables: //
     28// tab-width: 4 //
     29// mode: c++ //
     30// compile-command: "make install" //
     31// End: //
  • src/ResolvExpr/ExplodedActual.h

    r7951100 rb067d9b  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // Alternative.h --
     7// ExplodedActual.h --
    88//
    99// Author           : Aaron B. Moss
     
    3232
    3333                ExplodedActual() : env(), cost(Cost::zero), exprs() {}
    34 
    3534                ExplodedActual( const Alternative& actual, const SymTab::Indexer& indexer );
     35                ExplodedActual(ExplodedActual&&) = default;
     36                ExplodedActual& operator= (ExplodedActual&&) = default;
    3637        };
    3738}
     39
     40// Local Variables: //
     41// tab-width: 4 //
     42// mode: c++ //
     43// compile-command: "make install" //
     44// End: //
  • src/ResolvExpr/FindOpenVars.cc

    r7951100 rb067d9b  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 09:42:48 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun May 17 09:45:25 2015
    13 // Update Count     : 3
     11// Last Modified By : Andrew
     12// Last Modified On : Fri Jul 12 14:18:00 2019
     13// Update Count     : 4
    1414//
    1515
     
    1919#include <map>                    // for map<>::mapped_type
    2020
     21#include "AST/Pass.hpp"
     22#include "AST/Type.hpp"
    2123#include "Common/PassVisitor.h"
    2224#include "SynTree/Declaration.h"  // for TypeDecl, DeclarationWithType (ptr ...
     
    2426
    2527namespace ResolvExpr {
    26         struct FindOpenVars : public WithGuards {
    27                 FindOpenVars( OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen );
     28        struct FindOpenVars_old : public WithGuards {
     29                FindOpenVars_old( OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen );
    2830
    29                 void previsit( PointerType * pointerType );
    30                 void previsit( ArrayType * arrayType );
    31                 void previsit( FunctionType * functionType );
    32                 void previsit( TupleType * tupleType );
     31                void previsit( const PointerType * pointerType );
     32                void previsit( const ArrayType * arrayType );
     33                void previsit( const FunctionType * functionType );
     34                void previsit( const TupleType * tupleType );
    3335
    34                 void common_action( Type *type );
     36                void common_action( const Type *type );
    3537
    3638                OpenVarSet &openVars, &closedVars;
     
    3941        };
    4042
    41         void findOpenVars( Type *type, OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen ) {
    42                 PassVisitor<FindOpenVars> finder( openVars, closedVars, needAssertions, haveAssertions, firstIsOpen );
     43        void findOpenVars( const Type *type, OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen ) {
     44                PassVisitor<FindOpenVars_old> finder( openVars, closedVars, needAssertions, haveAssertions, firstIsOpen );
    4345                type->accept( finder );
    4446        }
    4547
    46         FindOpenVars::FindOpenVars( OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen )
     48        FindOpenVars_old::FindOpenVars_old( OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen )
    4749                : openVars( openVars ), closedVars( closedVars ), needAssertions( needAssertions ), haveAssertions( haveAssertions ), nextIsOpen( firstIsOpen ) {
    4850        }
    4951
    50         void FindOpenVars::common_action( Type *type ) {
     52        void FindOpenVars_old::common_action( const Type * type ) {
    5153                if ( nextIsOpen ) {
    52                         for ( Type::ForallList::const_iterator i = type->get_forall().begin(); i != type->get_forall().end(); ++i ) {
     54                        for ( Type::ForallList::const_iterator i = type->forall.begin(); i != type->forall.end(); ++i ) {
    5355                                openVars[ (*i)->get_name() ] = TypeDecl::Data{ (*i) };
    5456                                for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {
     
    5961                        }
    6062                } else {
    61                         for ( Type::ForallList::const_iterator i = type->get_forall().begin(); i != type->get_forall().end(); ++i ) {
     63                        for ( Type::ForallList::const_iterator i = type->forall.begin(); i != type->forall.end(); ++i ) {
    6264                                closedVars[ (*i)->get_name() ] = TypeDecl::Data{ (*i) };
    6365                                for ( std::list< DeclarationWithType* >::const_iterator assert = (*i)->get_assertions().begin(); assert != (*i)->get_assertions().end(); ++assert ) {
     
    7678        }
    7779
    78         void FindOpenVars::previsit(PointerType *pointerType) {
     80        void FindOpenVars_old::previsit(const PointerType * pointerType) {
    7981                common_action( pointerType );
    8082        }
    8183
    82         void FindOpenVars::previsit(ArrayType *arrayType) {
     84        void FindOpenVars_old::previsit(const ArrayType * arrayType) {
    8385                common_action( arrayType );
    8486        }
    8587
    86         void FindOpenVars::previsit(FunctionType *functionType) {
     88        void FindOpenVars_old::previsit(const FunctionType * functionType) {
    8789                common_action( functionType );
    8890                nextIsOpen = ! nextIsOpen;
     
    9092        }
    9193
    92         void FindOpenVars::previsit(TupleType *tupleType) {
     94        void FindOpenVars_old::previsit(const TupleType * tupleType) {
    9395                common_action( tupleType );
     96        }
     97
     98        namespace {
     99                struct FindOpenVars_new final : public ast::WithGuards {
     100                        ast::OpenVarSet & open;
     101                        ast::OpenVarSet & closed;
     102                        ast::AssertionSet & need;
     103                        ast::AssertionSet & have;
     104                        bool nextIsOpen;
     105
     106                        FindOpenVars_new(
     107                                ast::OpenVarSet & o, ast::OpenVarSet & c, ast::AssertionSet & n,
     108                                ast::AssertionSet & h, FirstMode firstIsOpen )
     109                        : open( o ), closed( c ), need( n ), have( h ), nextIsOpen( firstIsOpen ) {}
     110
     111                        void previsit( const ast::FunctionType * type ) {
     112                                // mark open/closed variables
     113                                if ( nextIsOpen ) {
     114                                        for ( const ast::TypeDecl * decl : type->forall ) {
     115                                                open[ decl->name ] = ast::TypeDecl::Data{ decl };
     116                                                for ( const ast::DeclWithType * assert : decl->assertions ) {
     117                                                        need[ assert ].isUsed = false;
     118                                                }
     119                                        }
     120                                } else {
     121                                        for ( const ast::TypeDecl * decl : type->forall ) {
     122                                                closed[ decl->name ] = ast::TypeDecl::Data{ decl };
     123                                                for ( const ast::DeclWithType * assert : decl->assertions ) {
     124                                                        have[ assert ].isUsed = false;
     125                                                }
     126                                        }
     127                                }
     128
     129                                // flip open variables for contained function types
     130                                nextIsOpen = ! nextIsOpen;
     131                                GuardAction( [this](){ nextIsOpen = ! nextIsOpen; } );
     132                        }
     133
     134                };
     135        }
     136
     137        void findOpenVars(
     138                        const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed,
     139                        ast::AssertionSet & need, ast::AssertionSet & have, FirstMode firstIsOpen ) {
     140                ast::Pass< FindOpenVars_new > finder{ open, closed, need, have, firstIsOpen };
     141                type->accept( finder );
    94142        }
    95143} // namespace ResolvExpr
  • src/ResolvExpr/FindOpenVars.h

    r7951100 rb067d9b  
    1616#pragma once
    1717
     18#include "AST/TypeEnvironment.hpp"  // for AssertionSet, OpenVarSet
    1819#include "ResolvExpr/TypeEnvironment.h"  // for AssertionSet, OpenVarSet
    1920
    2021class Type;
     22namespace ast {
     23        class Type;
     24}
    2125
    2226namespace ResolvExpr {
    2327        // Updates open and closed variables and their associated assertions
    24         void findOpenVars( Type *type, OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen );
     28        void findOpenVars( const Type *type, OpenVarSet &openVars, OpenVarSet &closedVars, AssertionSet &needAssertions, AssertionSet &haveAssertions, bool firstIsOpen );
     29
     30        enum FirstMode { FirstClosed, FirstOpen };
     31
     32        // Updates open and closed variables and their associated assertions
     33        void findOpenVars(
     34                const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed,
     35                ast::AssertionSet & need, ast::AssertionSet & have, FirstMode firstIsOpen );
    2536} // namespace ResolvExpr
    2637
  • src/ResolvExpr/Occurs.cc

    r7951100 rb067d9b  
    2424        struct Occurs : public WithVisitorRef<Occurs> {
    2525                Occurs( std::string varName, const TypeEnvironment &env );
    26                 void previsit( TypeInstType * typeInst );
     26                void previsit( const TypeInstType * typeInst );
    2727
    2828                bool result;
     
    3131        };
    3232
    33         bool occurs( Type *type, std::string varName, const TypeEnvironment &env ) {
     33        bool occurs( const Type *type, const std::string & varName, const TypeEnvironment &env ) {
    3434                PassVisitor<Occurs> occur( varName, env );
    3535                type->accept( occur );
     
    4545        }
    4646
    47         void Occurs::previsit( TypeInstType * typeInst ) {
     47        void Occurs::previsit( const TypeInstType * typeInst ) {
    4848                ///   std::cerr << "searching for vars: ";
    4949///   std::copy( eqvVars.begin(), eqvVars.end(), std::ostream_iterator< std::string >( std::cerr, " " ) );
  • src/ResolvExpr/PolyCost.cc

    r7951100 rb067d9b  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 09:50:12 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun May 17 09:52:02 2015
    13 // Update Count     : 3
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Jun 19 10:45:00 2019
     13// Update Count     : 4
    1414//
    1515
     16#include "AST/SymbolTable.hpp"
     17#include "AST/Type.hpp"
     18#include "AST/TypeEnvironment.hpp"
    1619#include "Common/PassVisitor.h"
    1720#include "SymTab/Indexer.h"   // for Indexer
     
    5457        }
    5558
     59// TODO: When the old PolyCost is torn out get rid of the _new suffix.
     60struct PolyCost_new {
     61        int result;
     62        const ast::SymbolTable &symtab;
     63        const ast::TypeEnvironment &env_;
     64
     65        PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) :
     66                result( 0 ), symtab( symtab ), env_( env ) {}
     67
     68        void previsit( const ast::TypeInstType * type ) {
     69                if ( const ast::EqvClass * eqv = env_.lookup( type->name ) ) /* && */ if ( eqv->bound ) {
     70                        if ( const ast::TypeInstType * otherType = eqv->bound.as< ast::TypeInstType >() ) {
     71                                if ( symtab.lookupType( otherType->name ) ) {
     72                                        // Bound to opaque type.
     73                                        result += 1;
     74                                }
     75                        } else {
     76                                // Bound to concrete type.
     77                                result += 1;
     78                        }
     79                }
     80        }
     81};
     82
     83int polyCost(
     84        const ast::Type * type, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
     85) {
     86        ast::Pass<PolyCost_new> costing( symtab, env );
     87        type->accept( costing );
     88        return costing.pass.result;
     89}
     90
    5691} // namespace ResolvExpr
    5792
  • src/ResolvExpr/PtrsAssignable.cc

    r7951100 rb067d9b  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 11:44:11 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Mar  2 17:36:05 2016
    13 // Update Count     : 8
    14 //
    15 
     11// Last Modified By : Andrew
     12// Last Modified On : Mon Jun 24 15:29:00 2019
     13// Update Count     : 9
     14//
     15
     16#include "typeops.h"
     17
     18#include "AST/Pass.hpp"
     19#include "AST/Type.hpp"
     20#include "AST/TypeEnvironment.hpp"
    1621#include "Common/PassVisitor.h"
    1722#include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
     
    2227namespace ResolvExpr {
    2328        struct PtrsAssignable : public WithShortCircuiting {
    24                 PtrsAssignable( Type *dest, const TypeEnvironment &env );
     29                PtrsAssignable( const Type * dest, const TypeEnvironment &env );
    2530
    2631                int get_result() const { return result; }
    2732
    28                 void previsit( Type * ) { visit_children = false; }
    29 
    30                 void postvisit( VoidType * voidType );
    31                 void postvisit( BasicType * basicType );
    32                 void postvisit( PointerType * pointerType );
    33                 void postvisit( ArrayType * arrayType );
    34                 void postvisit( FunctionType * functionType );
    35                 void postvisit( StructInstType * inst );
    36                 void postvisit( UnionInstType * inst );
    37                 void postvisit( EnumInstType * inst );
    38                 void postvisit( TraitInstType * inst );
    39                 void postvisit( TypeInstType * inst );
    40                 void postvisit( TupleType * tupleType );
    41                 void postvisit( VarArgsType * varArgsType );
    42                 void postvisit( ZeroType * zeroType );
    43                 void postvisit( OneType * oneType );
     33                void previsit( const Type * ) { visit_children = false; }
     34
     35                void postvisit( const VoidType * voidType );
     36                void postvisit( const BasicType * basicType );
     37                void postvisit( const PointerType * pointerType );
     38                void postvisit( const ArrayType * arrayType );
     39                void postvisit( const FunctionType * functionType );
     40                void postvisit( const StructInstType * inst );
     41                void postvisit( const UnionInstType * inst );
     42                void postvisit( const EnumInstType * inst );
     43                void postvisit( const TraitInstType * inst );
     44                void postvisit( const TypeInstType * inst );
     45                void postvisit( const TupleType * tupleType );
     46                void postvisit( const VarArgsType * varArgsType );
     47                void postvisit( const ZeroType * zeroType );
     48                void postvisit( const OneType * oneType );
    4449          private:
    45                 Type *dest;
     50                const Type * dest;
    4651                int result;
    4752                const TypeEnvironment &env;
    4853        };
    4954
    50         int ptrsAssignable( Type *src, Type *dest, const TypeEnvironment &env ) {
     55        int ptrsAssignable( const Type *src, const Type * dest, const TypeEnvironment &env ) {
    5156                // std::cerr << "assignable: " << src << " | " << dest << std::endl;
    52                 if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) {
    53                         if ( const EqvClass *eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {
     57                if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType* >( dest ) ) {
     58                        if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {
    5459                                return ptrsAssignable( src, eqvClass->type, env );
    5560                        } // if
    5661                } // if
    57                 if ( dynamic_cast< VoidType* >( dest ) ) {
     62                if ( dynamic_cast< const VoidType* >( dest ) ) {
    5863                        // void * = T * for any T is unsafe
    5964                        // xxx - this should be safe, but that currently breaks the build
     
    6671        }
    6772
    68         PtrsAssignable::PtrsAssignable( Type *dest, const TypeEnvironment &env ) : dest( dest ), result( 0 ), env( env ) {}
    69 
    70         void PtrsAssignable::postvisit( VoidType * ) {
     73        PtrsAssignable::PtrsAssignable( const Type * dest, const TypeEnvironment &env ) : dest( dest ), result( 0 ), env( env ) {}
     74
     75        void PtrsAssignable::postvisit( const VoidType * ) {
    7176                // T * = void * is disallowed - this is a change from C, where any
    7277                // void * can be assigned or passed to a non-void pointer without a cast.
    7378        }
    7479
    75         void PtrsAssignable::postvisit( __attribute__((unused)) BasicType *basicType ) {}
    76         void PtrsAssignable::postvisit( __attribute__((unused)) PointerType *pointerType ) {}
    77         void PtrsAssignable::postvisit( __attribute__((unused)) ArrayType *arrayType ) {}
    78         void PtrsAssignable::postvisit( __attribute__((unused)) FunctionType *functionType ) {}
    79 
    80         void PtrsAssignable::postvisit(  __attribute__((unused)) StructInstType *inst ) {}
    81         void PtrsAssignable::postvisit(  __attribute__((unused)) UnionInstType *inst ) {}
    82 
    83         void PtrsAssignable::postvisit( EnumInstType * ) {
    84                 if ( dynamic_cast< BasicType* >( dest ) ) {
     80        void PtrsAssignable::postvisit( const BasicType * ) {}
     81        void PtrsAssignable::postvisit( const PointerType * ) {}
     82        void PtrsAssignable::postvisit( const ArrayType * ) {}
     83        void PtrsAssignable::postvisit( const FunctionType * ) {}
     84
     85        void PtrsAssignable::postvisit( const StructInstType * ) {}
     86        void PtrsAssignable::postvisit( const UnionInstType * ) {}
     87
     88        void PtrsAssignable::postvisit( const EnumInstType * ) {
     89                if ( dynamic_cast< const BasicType* >( dest ) ) {
    8590                        // int * = E *, etc. is safe. This isn't technically correct, as each
    8691                        // enum has one basic type that it is compatible with, an that type can
     
    9297        }
    9398
    94         void PtrsAssignable::postvisit(  __attribute__((unused)) TraitInstType *inst ) {}
    95         void PtrsAssignable::postvisit( TypeInstType *inst ) {
    96                 if ( const EqvClass *eqvClass = env.lookup( inst->get_name() ) ) {
     99        void PtrsAssignable::postvisit(  const TraitInstType * ) {}
     100        void PtrsAssignable::postvisit( const TypeInstType * inst ) {
     101                if ( const EqvClass * eqvClass = env.lookup( inst->name ) ) {
    97102                        if ( eqvClass->type ) {
    98103                                // T * = S * for any S depends on the type bound to T
     
    102107        }
    103108
    104         void PtrsAssignable::postvisit(  __attribute__((unused)) TupleType *tupleType ) {}
    105         void PtrsAssignable::postvisit(  __attribute__((unused)) VarArgsType *varArgsType ) {}
    106         void PtrsAssignable::postvisit(  __attribute__((unused)) ZeroType *zeroType ) {}
    107         void PtrsAssignable::postvisit(  __attribute__((unused)) OneType *oneType ) {}
     109        void PtrsAssignable::postvisit( const TupleType * ) {}
     110        void PtrsAssignable::postvisit( const VarArgsType * ) {}
     111        void PtrsAssignable::postvisit( const ZeroType * ) {}
     112        void PtrsAssignable::postvisit( const OneType * ) {}
     113
     114// TODO: Get rid of the `_new` suffix when the old version is removed.
     115struct PtrsAssignable_new : public ast::WithShortCircuiting {
     116        const ast::Type * dst;
     117        const ast::TypeEnvironment & typeEnv;
     118        int result;
     119
     120        PtrsAssignable_new( const ast::Type * dst, const ast::TypeEnvironment & env ) :
     121                dst( dst ), typeEnv( env ), result( 0 ) {}
     122
     123        void previsit( Type * ) { visit_children = false; }
     124
     125        void postvisit( const ast::EnumInstType * ) {
     126                if ( dynamic_cast< const ast::BasicType * >( dst ) ) {
     127                        // int * = E *, etc. is safe. This isn't technically correct, as each
     128                        // enum has one basic type that it is compatible with, an that type can
     129                        // differ from enum to enum. Without replicating GCC's internal logic,
     130                        // there is no way to know which type this particular enum is compatible
     131                        // with, so punt on this for now.
     132                        result = 1;
     133                }
     134        }
     135        void postvisit( const ast::TypeInstType * inst ) {
     136                if ( const ast::EqvClass * eqv = typeEnv.lookup( inst->name ) ) {
     137                        if ( eqv->bound ) {
     138                                // T * = S * for any S depends on the type bound to T
     139                                result = ptrsAssignable( eqv->bound, dst, typeEnv );
     140                        }
     141                }
     142        }
     143};
     144
     145int ptrsAssignable( const ast::Type * src, const ast::Type * dst,
     146                const ast::TypeEnvironment & env ) {
     147        if ( const ast::TypeInstType * dstAsInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
     148                if ( const ast::EqvClass * eqv = env.lookup( dstAsInst->name ) ) {
     149                        return ptrsAssignable( src, eqv->bound, env );
     150                }
     151        }
     152        if ( dynamic_cast< const ast::VoidType * >( dst ) ) {
     153                return -1;
     154        } else {
     155                ast::Pass<PtrsAssignable_new> visitor( dst, env );
     156                src->accept( visitor );
     157                return visitor.pass.result;
     158        }
     159
     160// see ticket #136 (this should be able to replace the visitor).
     161#if 0
     162        if ( const ast::TypeInstType * dstAsTypeInst =
     163                        dynamic_cast< const ast::TypeInstType* >( dst ) ) {
     164                if ( const ast::EqvClass * eqv = env.lookup( dstAsTypeInst->get_name() ) ) {
     165                        return ptrsAssignable( src, eqv->type, env );
     166                } // if
     167        } // if
     168        if ( dynamic_cast< VoidType* >( dst ) ) {
     169                // void * = T * for any T is unsafe
     170                // xxx - this should be safe, but that currently breaks the build
     171                return -1;
     172        } else if ( dynamic_cast< EnumInstType * >( src ) ) {
     173                if ( dynamic_cast< BasicType * >( dst ) ) {
     174                        // int * = E *, etc. is safe. This isn't technically correct, as each
     175                        // enum has one basic type that it is compatible with, an that type can
     176                        // differ from enum to enum. Without replicating GCC's internal logic,
     177                        // there is no way to know which type this particular enum is compatible
     178                        // with, so punt on this for now.
     179                        return 1;
     180                }
     181        } else if ( const ast::TypeInstType * typeInstType =
     182                        dynamic_cast< const ast::TypeInstType * >( src ) ) {
     183                if ( const ast::EqvClass * eqv = env.lookup( typeInstType->name ) ) {
     184                        if ( eqv->bound ) {
     185                                // T * = S * for any S depends on the type bound to T
     186                                return ptrsAssignable( eqv->bound, dst, env );
     187                        }
     188                }
     189        }
     190        return 0;
     191#endif
     192}
    108193
    109194} // namespace ResolvExpr
  • src/ResolvExpr/PtrsCastable.cc

    r7951100 rb067d9b  
    1414//
    1515
     16#include "AST/Decl.hpp"
     17#include "AST/Pass.hpp"
     18#include "AST/Type.hpp"
     19#include "AST/TypeEnvironment.hpp"
    1620#include "Common/PassVisitor.h"
    1721#include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
     
    2327
    2428namespace ResolvExpr {
    25         struct PtrsCastable : public WithShortCircuiting  {
     29        struct PtrsCastable_old : public WithShortCircuiting  {
    2630          public:
    27                 PtrsCastable( Type *dest, const TypeEnvironment &env, const SymTab::Indexer &indexer );
     31                PtrsCastable_old( const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer );
    2832
    2933                int get_result() const { return result; }
    3034
    31                 void previsit( Type * ) { visit_children = false; }
    32 
    33                 void postvisit( VoidType * voidType );
    34                 void postvisit( BasicType * basicType );
    35                 void postvisit( PointerType * pointerType );
    36                 void postvisit( ArrayType * arrayType );
    37                 void postvisit( FunctionType * functionType );
    38                 void postvisit( StructInstType * inst );
    39                 void postvisit( UnionInstType * inst );
    40                 void postvisit( EnumInstType * inst );
    41                 void postvisit( TraitInstType * inst );
    42                 void postvisit( TypeInstType * inst );
    43                 void postvisit( TupleType * tupleType );
    44                 void postvisit( VarArgsType * varArgsType );
    45                 void postvisit( ZeroType * zeroType );
    46                 void postvisit( OneType * oneType );
     35                void previsit( const Type * ) { visit_children = false; }
     36
     37                void postvisit( const VoidType * voidType );
     38                void postvisit( const BasicType * basicType );
     39                void postvisit( const PointerType * pointerType );
     40                void postvisit( const ArrayType * arrayType );
     41                void postvisit( const FunctionType * functionType );
     42                void postvisit( const StructInstType * inst );
     43                void postvisit( const UnionInstType * inst );
     44                void postvisit( const EnumInstType * inst );
     45                void postvisit( const TraitInstType * inst );
     46                void postvisit( const TypeInstType * inst );
     47                void postvisit( const TupleType * tupleType );
     48                void postvisit( const VarArgsType * varArgsType );
     49                void postvisit( const ZeroType * zeroType );
     50                void postvisit( const OneType * oneType );
    4751          private:
    48                 Type *dest;
     52                const Type * dest;
    4953                int result;
    5054                const TypeEnvironment &env;
     
    5357
    5458        namespace {
    55                 int objectCast( Type *src, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
    56                         if ( dynamic_cast< FunctionType* >( src ) ) {
     59                int objectCast( const Type * src, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
     60                        if ( dynamic_cast< const FunctionType* >( src ) ) {
    5761                                return -1;
    58                         } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( src ) ) {
    59                                 if ( NamedTypeDecl *ntDecl = indexer.lookupType( typeInst->get_name() ) ) {
    60                                         if ( TypeDecl *tyDecl = dynamic_cast< TypeDecl* >( ntDecl ) ) {
    61                                                 if ( tyDecl->get_kind() == TypeDecl::Ftype ) {
     62                        } else if ( const TypeInstType * typeInst = dynamic_cast< const TypeInstType* >( src ) ) {
     63                                if ( const NamedTypeDecl * ntDecl = indexer.lookupType( typeInst->name ) ) {
     64                                        if ( const TypeDecl * tyDecl = dynamic_cast< const TypeDecl* >( ntDecl ) ) {
     65                                                if ( tyDecl->kind == TypeDecl::Ftype ) {
    6266                                                        return -1;
    6367                                                } // if
    6468                                        } //if
    65                                 } else if ( const EqvClass *eqvClass = env.lookup( typeInst->get_name() ) ) {
     69                                } else if ( const EqvClass * eqvClass = env.lookup( typeInst->get_name() ) ) {
    6670                                        if ( eqvClass->data.kind == TypeDecl::Ftype ) {
    6771                                                return -1;
     
    7175                        return 1;
    7276                }
    73                 int functionCast( Type *src, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
     77                int functionCast( const Type * src, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
    7478                        return -1 * objectCast( src, env, indexer );  // reverse the sense of objectCast
    7579                }
    7680        }
    7781
    78         int ptrsCastable( Type *src, Type *dest, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
    79                 if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) {
    80                         if ( const EqvClass *eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {
     82        int ptrsCastable( const Type * src, const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
     83                if ( const TypeInstType * destAsTypeInst = dynamic_cast< const TypeInstType* >( dest ) ) {
     84                        if ( const EqvClass * eqvClass = env.lookup( destAsTypeInst->get_name() ) ) {
    8185                                // xxx - should this be ptrsCastable?
    8286                                return ptrsAssignable( src, eqvClass->type, env );
    8387                        } // if
    8488                } // if
    85                 if ( dynamic_cast< VoidType* >( dest ) ) {
     89                if ( dynamic_cast< const VoidType* >( dest ) ) {
    8690                        return objectCast( src, env, indexer );
    8791                } else {
    88                         PassVisitor<PtrsCastable> ptrs( dest, env, indexer );
     92                        PassVisitor<PtrsCastable_old> ptrs( dest, env, indexer );
    8993                        src->accept( ptrs );
    9094                        return ptrs.pass.get_result();
     
    9296        }
    9397
    94         PtrsCastable::PtrsCastable( Type *dest, const TypeEnvironment &env, const SymTab::Indexer &indexer )
     98        PtrsCastable_old::PtrsCastable_old( const Type * dest, const TypeEnvironment &env, const SymTab::Indexer &indexer )
    9599                : dest( dest ), result( 0 ), env( env ), indexer( indexer )     {
    96100        }
    97101
    98         void PtrsCastable::postvisit( VoidType * ) {
    99                 result = objectCast( dest, env, indexer );
    100         }
    101 
    102         void PtrsCastable::postvisit( BasicType * ) {
    103                 result = objectCast( dest, env, indexer );
    104         }
    105 
    106         void PtrsCastable::postvisit( PointerType * ) {
    107                 result = objectCast( dest, env, indexer );
    108         }
    109 
    110         void PtrsCastable::postvisit( ArrayType * ) {
    111                 result = objectCast( dest, env, indexer );
    112         }
    113 
    114         void PtrsCastable::postvisit( FunctionType * ) {
     102        void PtrsCastable_old::postvisit( const VoidType * ) {
     103                result = objectCast( dest, env, indexer );
     104        }
     105
     106        void PtrsCastable_old::postvisit( const BasicType * ) {
     107                result = objectCast( dest, env, indexer );
     108        }
     109
     110        void PtrsCastable_old::postvisit( const PointerType * ) {
     111                result = objectCast( dest, env, indexer );
     112        }
     113
     114        void PtrsCastable_old::postvisit( const ArrayType * ) {
     115                result = objectCast( dest, env, indexer );
     116        }
     117
     118        void PtrsCastable_old::postvisit( const FunctionType * ) {
    115119                // result = -1;
    116120                result = functionCast( dest, env, indexer );
    117121        }
    118122
    119         void PtrsCastable::postvisit( StructInstType * ) {
    120                 result = objectCast( dest, env, indexer );
    121         }
    122 
    123         void PtrsCastable::postvisit( UnionInstType * ) {
    124                 result = objectCast( dest, env, indexer );
    125         }
    126 
    127         void PtrsCastable::postvisit( EnumInstType * ) {
    128                 if ( dynamic_cast< EnumInstType* >( dest ) ) {
     123        void PtrsCastable_old::postvisit( const StructInstType * ) {
     124                result = objectCast( dest, env, indexer );
     125        }
     126
     127        void PtrsCastable_old::postvisit( const UnionInstType * ) {
     128                result = objectCast( dest, env, indexer );
     129        }
     130
     131        void PtrsCastable_old::postvisit( const EnumInstType * ) {
     132                if ( dynamic_cast< const EnumInstType * >( dest ) ) {
    129133                        result = 1;
    130                 } else if ( BasicType *bt = dynamic_cast< BasicType* >( dest ) ) {
    131                         if ( bt->get_kind() == BasicType::SignedInt ) {
     134                } else if ( const BasicType * bt = dynamic_cast< const BasicType * >( dest ) ) {
     135                        if ( bt->kind == BasicType::SignedInt ) {
    132136                                result = 0;
    133137                        } else {
     
    139143        }
    140144
    141         void PtrsCastable::postvisit( TraitInstType * ) {}
    142 
    143         void PtrsCastable::postvisit(TypeInstType *inst) {
     145        void PtrsCastable_old::postvisit( const TraitInstType * ) {}
     146
     147        void PtrsCastable_old::postvisit( const TypeInstType *inst ) {
    144148                //result = objectCast( inst, env, indexer ) > 0 && objectCast( dest, env, indexer ) > 0 ? 1 : -1;
    145149                result = objectCast( inst, env, indexer ) == objectCast( dest, env, indexer ) ? 1 : -1;
    146150        }
    147151
    148         void PtrsCastable::postvisit( TupleType * ) {
    149                 result = objectCast( dest, env, indexer );
    150         }
    151 
    152         void PtrsCastable::postvisit( VarArgsType * ) {
    153                 result = objectCast( dest, env, indexer );
    154         }
    155 
    156         void PtrsCastable::postvisit( ZeroType * ) {
    157                 result = objectCast( dest, env, indexer );
    158         }
    159 
    160         void PtrsCastable::postvisit( OneType * ) {
    161                 result = objectCast( dest, env, indexer );
    162         }
     152        void PtrsCastable_old::postvisit( const TupleType * ) {
     153                result = objectCast( dest, env, indexer );
     154        }
     155
     156        void PtrsCastable_old::postvisit( const VarArgsType * ) {
     157                result = objectCast( dest, env, indexer );
     158        }
     159
     160        void PtrsCastable_old::postvisit( const ZeroType * ) {
     161                result = objectCast( dest, env, indexer );
     162        }
     163
     164        void PtrsCastable_old::postvisit( const OneType * ) {
     165                result = objectCast( dest, env, indexer );
     166        }
     167
     168namespace {
     169        // can this type be cast to an object (1 for yes, -1 for no)
     170        int objectCast(
     171                const ast::Type * src, const ast::TypeEnvironment & env, const ast::SymbolTable & symtab
     172        ) {
     173                if ( dynamic_cast< const ast::FunctionType * >( src ) ) {
     174                        return -1;
     175                } else if ( auto inst = dynamic_cast< const ast::TypeInstType * >( src ) ) {
     176                        if ( const ast::NamedTypeDecl * named = symtab.lookupType( inst->name ) ) {
     177                                if ( auto tyDecl = dynamic_cast< const ast::TypeDecl * >( named ) ) {
     178                                        if ( tyDecl->kind == ast::TypeVar::Ftype ) {
     179                                                return -1;
     180                                        }
     181                                }
     182                        } else if ( const ast::EqvClass * eqvClass = env.lookup( inst->name ) ) {
     183                                if ( eqvClass->data.kind == ast::TypeVar::Ftype ) {
     184                                        return -1;
     185                                }
     186                        }
     187                }
     188
     189                return 1;
     190        }
     191
     192        // can this type be cast to a function (inverse of objectCast)
     193        int functionCast(
     194                const ast::Type * src, const ast::TypeEnvironment & env, const ast::SymbolTable & symtab
     195        ) {
     196                return -1 * objectCast( src, env, symtab );
     197        }
     198
     199        class PtrsCastable_new : public ast::WithShortCircuiting {
     200                const ast::Type * dst;
     201                const ast::TypeEnvironment & env;
     202                const ast::SymbolTable & symtab;
     203        public:
     204                int result;
     205
     206                PtrsCastable_new(
     207                        const ast::Type * d, const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
     208                : dst( d ), env( e ), symtab( syms ), result( 0 ) {}
     209
     210                void previsit( const ast::Type * ) { visit_children = false; }
     211
     212                void postvisit( const ast::VoidType * ) {
     213                        result = objectCast( dst, env, symtab );
     214                }
     215
     216                void postvisit( const ast::BasicType * ) {
     217                        result = objectCast( dst, env, symtab );
     218                }
     219
     220                void postvisit( const ast::PointerType * ) {
     221                        result = objectCast( dst, env, symtab );
     222                }
     223
     224                void postvisit( const ast::ArrayType * ) {
     225                        result = objectCast( dst, env, symtab );
     226                }
     227
     228                void postvisit( const ast::FunctionType * ) {
     229                        result = functionCast( dst, env, symtab );
     230                }
     231
     232                void postvisit( const ast::StructInstType * ) {
     233                        result = objectCast( dst, env, symtab );
     234                }
     235
     236                void postvisit( const ast::UnionInstType * ) {
     237                        result = objectCast( dst, env, symtab );
     238                }
     239
     240                void postvisit( const ast::EnumInstType * ) {
     241                        if ( dynamic_cast< const ast::EnumInstType * >( dst ) ) {
     242                                result = 1;
     243                        } else if ( auto bt = dynamic_cast< const ast::BasicType * >( dst ) ) {
     244                                if ( bt->kind == ast::BasicType::SignedInt ) {
     245                                        result = 0;
     246                                } else {
     247                                        result = 1;
     248                                }
     249                        } else {
     250                                result = objectCast( dst, env, symtab );
     251                        }
     252                }
     253
     254                void postvisit( const ast::TraitInstType * ) {}
     255
     256                void postvisit( const ast::TypeInstType * inst ) {
     257                        // check trait and destination type are both object or both function
     258                        result = objectCast( inst, env, symtab ) == objectCast( dst, env, symtab ) ? 1 : -1;
     259                }
     260
     261                void postvisit( const ast::TupleType * ) {
     262                        result = objectCast( dst, env, symtab );
     263                }
     264
     265                void postvisit( const ast::VarArgsType * ) {
     266                        result = objectCast( dst, env, symtab );
     267                }
     268
     269                void postvisit( const ast::ZeroType * ) {
     270                        result = objectCast( dst, env, symtab );
     271                }
     272
     273                void postvisit( const ast::OneType * ) {
     274                        result = objectCast( dst, env, symtab );
     275                }
     276
     277        };
     278} // anonymous namespace
     279
     280int ptrsCastable(
     281        const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
     282        const ast::TypeEnvironment & env
     283) {
     284        if ( auto inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
     285                if ( const ast::EqvClass * eqvClass = env.lookup( inst->name ) ) {
     286                        return ptrsAssignable( src, eqvClass->bound, env );
     287                }
     288        }
     289
     290        if ( dynamic_cast< const ast::VoidType * >( dst ) ) {
     291                return objectCast( src, env, symtab );
     292        } else {
     293                ast::Pass< PtrsCastable_new > ptrs{ dst, env, symtab };
     294                src->accept( ptrs );
     295                return ptrs.pass.result;
     296        }
     297}
     298
    163299} // namespace ResolvExpr
    164300
  • src/ResolvExpr/RenameVars.cc

    r7951100 rb067d9b  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 12:05:18 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Mar  2 17:36:32 2016
    13 // Update Count     : 5
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr Jun 20 17:39:00 2019
     13// Update Count     : 8
    1414//
    1515
     
    1919#include <utility>                 // for pair
    2020
     21#include "AST/Pass.hpp"
     22#include "AST/Type.hpp"
    2123#include "Common/PassVisitor.h"
     24#include "Common/ScopedMap.h"
    2225#include "Common/SemanticError.h"  // for SemanticError
    2326#include "RenameVars.h"
     
    2831
    2932namespace ResolvExpr {
    30         namespace {
    31                 struct RenameVars {
    32                         RenameVars();
    33                         void reset();
    3433
    35                         void previsit( TypeInstType * instType );
    36                         void previsit( Type * );
    37                         void postvisit( Type * );
     34namespace {
     35        class RenamingData {
     36                int level = 0;
     37                int resetCount = 0;
     38                ScopedMap< std::string, std::string > nameMap;
    3839
    39                   private:
    40                         int level, resetCount;
    41                         std::list< std::map< std::string, std::string > > mapStack;
    42                 };
    43 
    44                 PassVisitor<RenameVars> global_renamer;
    45         } // namespace
    46 
    47         void renameTyVars( Type * t ) {
    48                 t->accept( global_renamer );
    49         }
    50 
    51         void resetTyVarRenaming() {
    52                 global_renamer.pass.reset();
    53         }
    54 
    55         namespace {
    56                 RenameVars::RenameVars() : level( 0 ), resetCount( 0 ) {
    57                         mapStack.push_front( std::map< std::string, std::string >() );
     40        public:
     41                void reset() {
     42                        level = 0;
     43                        ++resetCount;
    5844                }
    5945
    60                 void RenameVars::reset() {
    61                         level = 0;
    62                         resetCount++;
     46                using mapConstIterator = ScopedMap< std::string, std::string >::const_iterator;
     47
     48                void rename( TypeInstType * type ) {
     49                        mapConstIterator it = nameMap.find( type->name );
     50                        if ( it != nameMap.end() ) {
     51                                type->name = it->second;
     52                        }
    6353                }
    6454
    65                 void RenameVars::previsit( TypeInstType * instType ) {
    66                         previsit( (Type *)instType );
    67                         std::map< std::string, std::string >::const_iterator i = mapStack.front().find( instType->name );
    68                         if ( i != mapStack.front().end() ) {
    69                                 instType->name = i->second;
    70                         } // if
    71                 }
    72 
    73                 void RenameVars::previsit( Type * type ) {
     55                void openLevel( Type * type ) {
    7456                        if ( ! type->forall.empty() ) {
    75                                 // copies current name mapping into new mapping
    76                                 mapStack.push_front( mapStack.front() );
     57                                nameMap.beginScope();
    7758                                // renames all "forall" type names to `_${level}_${name}'
    7859                                for ( auto td : type->forall ) {
     
    8061                                        output << "_" << resetCount << "_" << level << "_" << td->name;
    8162                                        std::string newname( output.str() );
    82                                         mapStack.front()[ td->get_name() ] = newname;
     63                                        nameMap[ td->get_name() ] = newname;
    8364                                        td->name = newname;
    8465                                        // ditto for assertion names, the next level in
     
    8970                }
    9071
    91                 void RenameVars::postvisit( Type * type ) {
    92                         // clears name mapping added by typeBefore()
    93                         if ( ! type->forall.empty() ) {
    94                                 mapStack.pop_front();
    95                         } // if
     72                void closeLevel( Type * type ) {
     73                        if ( !type->forall.empty() ) {
     74                                nameMap.endScope();
     75                        }
    9676                }
    97         } // namespace
     77
     78                const ast::TypeInstType * rename( const ast::TypeInstType * type ) {
     79                        mapConstIterator it = nameMap.find( type->name );
     80                        if ( it != nameMap.end() ) {
     81                                ast::TypeInstType * mutType = ast::mutate( type );
     82                                mutType->name = it->second;
     83                    type = mutType;
     84                        }
     85                        return type;
     86                }
     87
     88                template<typename NodeT>
     89                const NodeT * openLevel( const NodeT * type ) {
     90                        if ( !type->forall.empty() ) {
     91                                nameMap.beginScope();
     92                                // Load new names from this forall clause and perform renaming.
     93                                NodeT * mutType = ast::mutate( type );
     94                                for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) {
     95                                        std::ostringstream output;
     96                                        output << "_" << resetCount << "_" << level << "_" << td->name;
     97                                        std::string newname( output.str() );
     98                                        nameMap[ td->name ] = newname;
     99                                        ++level;
     100
     101                                        ast::TypeDecl * decl = ast::mutate( td.get() );
     102                                        decl->name = newname;
     103                                        td = decl;
     104                                }
     105                        }
     106                        return type;
     107                }
     108
     109                template<typename NodeT>
     110                const NodeT * closeLevel( const NodeT * type ) {
     111                        if ( !type->forall.empty() ) {
     112                                nameMap.endScope();
     113                        }
     114                        return type;
     115                }
     116        };
     117
     118        // Global State:
     119        RenamingData renaming;
     120
     121        struct RenameVars {
     122                void previsit( TypeInstType * instType ) {
     123                        renaming.openLevel( (Type*)instType );
     124                        renaming.rename( instType );
     125                }
     126                void previsit( Type * type ) {
     127                        renaming.openLevel( type );
     128                }
     129                void postvisit( Type * type ) {
     130                        renaming.closeLevel( type );
     131                }
     132
     133                const ast::FunctionType * previsit( const ast::FunctionType * type ) {
     134                        return renaming.openLevel( type );
     135                }
     136                const ast::StructInstType * previsit( const ast::StructInstType * type ) {
     137                        return renaming.openLevel( type );
     138                }
     139                const ast::UnionInstType * previsit( const ast::UnionInstType * type ) {
     140                        return renaming.openLevel( type );
     141                }
     142                const ast::TraitInstType * previsit( const ast::TraitInstType * type ) {
     143                        return renaming.openLevel( type );
     144                }
     145                const ast::TypeInstType * previsit( const ast::TypeInstType * type ) {
     146                        return renaming.rename( renaming.openLevel( type ) );
     147                }
     148                const ast::ParameterizedType * postvisit( const ast::ParameterizedType * type ) {
     149                        return renaming.closeLevel( type );
     150                }
     151        };
     152
     153} // namespace
     154
     155void renameTyVars( Type * t ) {
     156        PassVisitor<RenameVars> renamer;
     157        t->accept( renamer );
     158}
     159
     160const ast::Type * renameTyVars( const ast::Type * t ) {
     161        ast::Pass<RenameVars> renamer;
     162        return t->accept( renamer );
     163}
     164
     165void resetTyVarRenaming() {
     166        renaming.reset();
     167}
     168
    98169} // namespace ResolvExpr
    99170
  • src/ResolvExpr/RenameVars.h

    r7951100 rb067d9b  
    2323#include "SynTree/Visitor.h"  // for Visitor
    2424
     25namespace ast {
     26        class Type;
     27}
     28
    2529namespace ResolvExpr {
    2630        /// Provides a consistent renaming of forall type names in a hierarchy by prefixing them with a unique "level" ID
    2731        void renameTyVars( Type * );
     32        const ast::Type * renameTyVars( const ast::Type * );
    2833
    2934        /// resets internal state of renamer to avoid overflow
  • src/ResolvExpr/ResolveTypeof.cc

    r7951100 rb067d9b  
    1818#include <cassert>               // for assert
    1919
     20#include "AST/CVQualifiers.hpp"
     21#include "AST/Node.hpp"
     22#include "AST/Pass.hpp"
     23#include "AST/Type.hpp"
     24#include "AST/TypeEnvironment.hpp"
    2025#include "Common/PassVisitor.h"  // for PassVisitor
     26#include "Common/utility.h"      // for copy
    2127#include "Resolver.h"            // for resolveInVoidContext
    2228#include "SynTree/Expression.h"  // for Expression
     
    4248        }
    4349
    44         class ResolveTypeof : public WithShortCircuiting {
     50        class ResolveTypeof_old : public WithShortCircuiting {
    4551          public:
    46                 ResolveTypeof( const SymTab::Indexer &indexer ) : indexer( indexer ) {}
     52                ResolveTypeof_old( const SymTab::Indexer &indexer ) : indexer( indexer ) {}
    4753                void premutate( TypeofType *typeofType );
    4854                Type * postmutate( TypeofType *typeofType );
     
    5359
    5460        Type * resolveTypeof( Type *type, const SymTab::Indexer &indexer ) {
    55                 PassVisitor<ResolveTypeof> mutator( indexer );
     61                PassVisitor<ResolveTypeof_old> mutator( indexer );
    5662                return type->acceptMutator( mutator );
    5763        }
    5864
    59         void ResolveTypeof::premutate( TypeofType * ) {
     65        void ResolveTypeof_old::premutate( TypeofType * ) {
    6066                visit_children = false;
    6167        }
    6268
    63         Type * ResolveTypeof::postmutate( TypeofType *typeofType ) {
     69        Type * ResolveTypeof_old::postmutate( TypeofType *typeofType ) {
    6470#if 0
    6571                std::cerr << "resolving typeof: ";
     
    6773                std::cerr << std::endl;
    6874#endif
    69                 if ( typeofType->expr ) {
     75                // pass on null expression
     76                if ( ! typeofType->expr ) return typeofType;
     77
     78                bool isBasetypeof = typeofType->is_basetypeof;
     79                auto oldQuals = typeofType->get_qualifiers().val;
     80
     81                Type* newType;
     82                if ( TypeExpr* tyExpr = dynamic_cast<TypeExpr*>(typeofType->expr) ) {
     83                        // typeof wrapping type
     84                        newType = tyExpr->type;
     85                        tyExpr->type = nullptr;
     86                        delete tyExpr;
     87                } else {
     88                        // typeof wrapping expression
    7089                        Expression * newExpr = resolveInVoidContext( typeofType->expr, indexer );
    7190                        assert( newExpr->result && ! newExpr->result->isVoid() );
    72                         Type * newType = newExpr->result;
     91                        newType = newExpr->result;
    7392                        newExpr->result = nullptr;
    7493                        delete typeofType;
    7594                        delete newExpr;
     95                }
     96
     97                // clear qualifiers for base, combine with typeoftype quals in any case
     98                if ( isBasetypeof ) {
     99                        // replace basetypeof(<enum>) by int
     100                        if ( dynamic_cast<EnumInstType*>(newType) ) {
     101                                Type* newerType =
     102                                        new BasicType{ newType->get_qualifiers(), BasicType::SignedInt,
     103                                        newType->attributes };
     104                                delete newType;
     105                                newType = newerType;
     106                        }
     107                        newType->get_qualifiers().val
     108                                = ( newType->get_qualifiers().val & ~Type::Qualifiers::Mask ) | oldQuals;
     109                } else {
     110                        newType->get_qualifiers().val |= oldQuals;
     111                }
     112               
     113                return newType;
     114        }
     115
     116namespace {
     117        struct ResolveTypeof_new : public ast::WithShortCircuiting {
     118                const ast::SymbolTable & localSymtab;
     119
     120                ResolveTypeof_new( const ast::SymbolTable & syms ) : localSymtab( syms ) {}
     121
     122                void premutate( const ast::TypeofType * ) { visit_children = false; }
     123
     124                const ast::Type * postmutate( const ast::TypeofType * typeofType ) {
     125                        // pass on null expression
     126                        if ( ! typeofType->expr ) return typeofType;
     127
     128                        ast::ptr< ast::Type > newType;
     129                        if ( auto tyExpr = typeofType->expr.as< ast::TypeExpr >() ) {
     130                                // typeof wrapping type
     131                                newType = tyExpr->type;
     132                        } else {
     133                                // typeof wrapping expression
     134                                ast::TypeEnvironment dummy;
     135                                ast::ptr< ast::Expr > newExpr =
     136                                        resolveInVoidContext( typeofType->expr, localSymtab, dummy );
     137                                assert( newExpr->result && ! newExpr->result->isVoid() );
     138                                newType = newExpr->result;
     139                        }
     140
     141                        // clear qualifiers for base, combine with typeoftype quals regardless
     142                        if ( typeofType->kind == ast::TypeofType::Basetypeof ) {
     143                                // replace basetypeof(<enum>) by int
     144                                if ( newType.as< ast::EnumInstType >() ) {
     145                                        newType = new ast::BasicType{
     146                                                ast::BasicType::SignedInt, newType->qualifiers, copy(newType->attributes) };
     147                                }
     148                                reset_qualifiers(
     149                                        newType,
     150                                        ( newType->qualifiers & ~ast::CV::EquivQualifiers ) | typeofType->qualifiers );
     151                        } else {
     152                                add_qualifiers( newType, typeofType->qualifiers );
     153                        }
     154
    76155                        return newType;
    77                 } // if
    78                 return typeofType;
    79         }
     156                }
     157        };
     158} // anonymous namespace
     159
     160const ast::Type * resolveTypeof( const ast::Type * type , const ast::SymbolTable & symtab ) {
     161        ast::Pass< ResolveTypeof_new > mutator{ symtab };
     162        return type->accept( mutator );
     163}
     164
    80165} // namespace ResolvExpr
    81166
  • src/ResolvExpr/ResolveTypeof.h

    r7951100 rb067d9b  
    2020class Indexer;
    2121}  // namespace SymTab
     22namespace ast {
     23        class Type;
     24        class SymbolTable;
     25}
    2226
    2327namespace ResolvExpr {
    2428        Type *resolveTypeof( Type*, const SymTab::Indexer &indexer );
     29        const ast::Type * resolveTypeof( const ast::Type *, const ast::SymbolTable & );
    2530} // namespace ResolvExpr
    2631
  • src/ResolvExpr/Resolver.cc

    r7951100 rb067d9b  
    77// Resolver.cc --
    88//
    9 // Author           : Richard C. Bilson
     9// Author           : Aaron B. Moss
    1010// Created On       : Sun May 17 12:17:01 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Feb 17 11:19:40 2018
    13 // Update Count     : 213
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Wed May 29 11:00:00 2019
     13// Update Count     : 241
    1414//
    1515
    16 #include <stddef.h>                      // for NULL
    1716#include <cassert>                       // for strict_dynamic_cast, assert
    1817#include <memory>                        // for allocator, allocator_traits<...
    1918#include <tuple>                         // for get
    20 #include <vector>
     19#include <vector>                        // for vector
    2120
    2221#include "Alternative.h"                 // for Alternative, AltList
    2322#include "AlternativeFinder.h"           // for AlternativeFinder, resolveIn...
     23#include "Candidate.hpp"
     24#include "CandidateFinder.hpp"
     25#include "CurrentObject.h"               // for CurrentObject
     26#include "RenameVars.h"                  // for RenameVars, global_renamer
     27#include "Resolver.h"
     28#include "ResolvMode.h"                  // for ResolvMode
     29#include "typeops.h"                     // for extractResultType
     30#include "Unify.h"                       // for unify
     31#include "AST/Chain.hpp"
     32#include "AST/Decl.hpp"
     33#include "AST/Init.hpp"
     34#include "AST/Pass.hpp"
     35#include "AST/Print.hpp"
     36#include "AST/SymbolTable.hpp"
     37#include "AST/Type.hpp"
    2438#include "Common/PassVisitor.h"          // for PassVisitor
    2539#include "Common/SemanticError.h"        // for SemanticError
    2640#include "Common/utility.h"              // for ValueGuard, group_iterate
    27 #include "CurrentObject.h"               // for CurrentObject
    2841#include "InitTweak/GenInit.h"
    2942#include "InitTweak/InitTweak.h"         // for isIntrinsicSingleArgCallStmt
    30 #include "RenameVars.h"                  // for RenameVars, global_renamer
    3143#include "ResolvExpr/TypeEnvironment.h"  // for TypeEnvironment
    32 #include "ResolveTypeof.h"               // for resolveTypeof
    33 #include "Resolver.h"
    3444#include "SymTab/Autogen.h"              // for SizeType
    3545#include "SymTab/Indexer.h"              // for Indexer
     
    4252#include "SynTree/Visitor.h"             // for acceptAll, maybeAccept
    4353#include "Tuples/Tuples.h"
    44 #include "typeops.h"                     // for extractResultType
    45 #include "Unify.h"                       // for unify
     54#include "Validate/FindSpecialDecls.h"   // for SizeType
    4655
    4756using namespace std;
    4857
    4958namespace ResolvExpr {
    50         struct Resolver final : public WithIndexer, public WithGuards, public WithVisitorRef<Resolver>, public WithShortCircuiting, public WithStmtsToAdd {
    51                 Resolver() {}
    52                 Resolver( const SymTab::Indexer & other ) {
     59        struct Resolver_old final : public WithIndexer, public WithGuards, public WithVisitorRef<Resolver_old>, public WithShortCircuiting, public WithStmtsToAdd {
     60                Resolver_old() {}
     61                Resolver_old( const SymTab::Indexer & other ) {
    5362                        indexer = other;
    5463                }
    5564
    56                 void previsit( FunctionDecl *functionDecl );
    57                 void postvisit( FunctionDecl *functionDecl );
    58                 void previsit( ObjectDecl *objectDecll );
    59                 void previsit( TypeDecl *typeDecl );
     65                void previsit( FunctionDecl * functionDecl );
     66                void postvisit( FunctionDecl * functionDecl );
     67                void previsit( ObjectDecl * objectDecll );
    6068                void previsit( EnumDecl * enumDecl );
    6169                void previsit( StaticAssertDecl * assertDecl );
     
    6472                void previsit( PointerType * at );
    6573
    66                 void previsit( ExprStmt *exprStmt );
    67                 void previsit( AsmExpr *asmExpr );
    68                 void previsit( AsmStmt *asmStmt );
    69                 void previsit( IfStmt *ifStmt );
    70                 void previsit( WhileStmt *whileStmt );
    71                 void previsit( ForStmt *forStmt );
    72                 void previsit( SwitchStmt *switchStmt );
    73                 void previsit( CaseStmt *caseStmt );
    74                 void previsit( BranchStmt *branchStmt );
    75                 void previsit( ReturnStmt *returnStmt );
    76                 void previsit( ThrowStmt *throwStmt );
    77                 void previsit( CatchStmt *catchStmt );
     74                void previsit( ExprStmt * exprStmt );
     75                void previsit( AsmExpr * asmExpr );
     76                void previsit( AsmStmt * asmStmt );
     77                void previsit( IfStmt * ifStmt );
     78                void previsit( WhileStmt * whileStmt );
     79                void previsit( ForStmt * forStmt );
     80                void previsit( SwitchStmt * switchStmt );
     81                void previsit( CaseStmt * caseStmt );
     82                void previsit( BranchStmt * branchStmt );
     83                void previsit( ReturnStmt * returnStmt );
     84                void previsit( ThrowStmt * throwStmt );
     85                void previsit( CatchStmt * catchStmt );
    7886                void previsit( WaitForStmt * stmt );
    79                 void previsit( WithStmt * withStmt );
    80 
    81                 void previsit( SingleInit *singleInit );
    82                 void previsit( ListInit *listInit );
    83                 void previsit( ConstructorInit *ctorInit );
     87
     88                void previsit( SingleInit * singleInit );
     89                void previsit( ListInit * listInit );
     90                void previsit( ConstructorInit * ctorInit );
    8491          private:
    8592                typedef std::list< Initializer * >::iterator InitIterator;
     
    8895                void handlePtrType( PtrType * type );
    8996
    90                 void resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts );
    9197                void fallbackInit( ConstructorInit * ctorInit );
    9298
     
    96102        };
    97103
     104        struct ResolveWithExprs : public WithIndexer, public WithGuards, public WithVisitorRef<ResolveWithExprs>, public WithShortCircuiting, public WithStmtsToAdd {
     105                void previsit( FunctionDecl * );
     106                void previsit( WithStmt * );
     107
     108                void resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts );
     109        };
     110
    98111        void resolve( std::list< Declaration * > translationUnit ) {
    99                 PassVisitor<Resolver> resolver;
     112                PassVisitor<Resolver_old> resolver;
    100113                acceptAll( translationUnit, resolver );
    101114        }
    102115
    103         void resolveDecl( Declaration * decl, const SymTab::Indexer &indexer ) {
    104                 PassVisitor<Resolver> resolver( indexer );
     116        void resolveDecl( Declaration * decl, const SymTab::Indexer & indexer ) {
     117                PassVisitor<Resolver_old> resolver( indexer );
    105118                maybeAccept( decl, resolver );
    106119        }
    107120
    108121        namespace {
    109                 struct DeleteFinder : public WithShortCircuiting        {
     122                struct DeleteFinder_old : public WithShortCircuiting    {
    110123                        DeletedExpr * delExpr = nullptr;
    111124                        void previsit( DeletedExpr * expr ) {
     
    121134
    122135        DeletedExpr * findDeletedExpr( Expression * expr ) {
    123                 PassVisitor<DeleteFinder> finder;
     136                PassVisitor<DeleteFinder_old> finder;
    124137                expr->accept( finder );
    125138                return finder.pass.delExpr;
     
    127140
    128141        namespace {
    129                 struct StripCasts {
     142                struct StripCasts_old {
    130143                        Expression * postmutate( CastExpr * castExpr ) {
    131144                                if ( castExpr->isGenerated && ResolvExpr::typesCompatible( castExpr->arg->result, castExpr->result, SymTab::Indexer() ) ) {
     
    140153
    141154                        static void strip( Expression *& expr ) {
    142                                 PassVisitor<StripCasts> stripper;
     155                                PassVisitor<StripCasts_old> stripper;
    143156                                expr = expr->acceptMutator( stripper );
    144157                        }
    145158                };
    146159
    147                 void finishExpr( Expression *&expr, const TypeEnvironment &env, TypeSubstitution * oldenv = nullptr ) {
     160                void finishExpr( Expression *& expr, const TypeEnvironment & env, TypeSubstitution * oldenv = nullptr ) {
    148161                        expr->env = oldenv ? oldenv->clone() : new TypeSubstitution;
    149162                        env.makeSubstitution( *expr->env );
    150                         StripCasts::strip( expr ); // remove unnecessary casts that may be buried in an expression
     163                        StripCasts_old::strip( expr ); // remove unnecessary casts that may be buried in an expression
    151164                }
    152165
    153166                void removeExtraneousCast( Expression *& expr, const SymTab::Indexer & indexer ) {
    154167                        if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
    155                                 if ( ResolvExpr::typesCompatible( castExpr->arg->result, castExpr->result, indexer ) ) {
     168                                if ( typesCompatible( castExpr->arg->result, castExpr->result, indexer ) ) {
    156169                                        // cast is to the same type as its argument, so it's unnecessary -- remove it
    157170                                        expr = castExpr->arg;
     
    165178
    166179        namespace {
    167                 void findUnfinishedKindExpression(Expression * untyped, Alternative & alt, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, bool adjust = false, bool prune = true, bool failFast = true) {
     180                void findUnfinishedKindExpression(Expression * untyped, Alternative & alt, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{} ) {
    168181                        assertf( untyped, "expected a non-null expression." );
     182
     183                        // xxx - this isn't thread-safe, but should work until we parallelize the resolver
     184                        static unsigned recursion_level = 0;
     185
     186                        ++recursion_level;
    169187                        TypeEnvironment env;
    170188                        AlternativeFinder finder( indexer, env );
    171                         finder.find( untyped, adjust, prune, failFast );
     189                        finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );
     190                        --recursion_level;
    172191
    173192                        #if 0
     
    182201                        #endif
    183202
     203                        // produce filtered list of alternatives
    184204                        AltList candidates;
    185205                        for ( Alternative & alt : finder.get_alternatives() ) {
     
    189209                        }
    190210
    191                         // xxx - if > 1 alternative with same cost, ignore deleted and pick from remaining
    192                         // choose the lowest cost expression among the candidates
     211                        // produce invalid error if no candidates
     212                        if ( candidates.empty() ) {
     213                                SemanticError( untyped, toString( "No reasonable alternatives for ", kindStr, (kindStr != "" ? " " : ""), "expression: ") );
     214                        }
     215
     216                        // search for cheapest candidate
    193217                        AltList winners;
    194                         findMinCost( candidates.begin(), candidates.end(), back_inserter( winners ) );
    195                         if ( winners.size() == 0 ) {
    196                                 SemanticError( untyped, toString( "No reasonable alternatives for ", kindStr, (kindStr != "" ? " " : ""), "expression: ") );
    197                         } else if ( winners.size() != 1 ) {
     218                        bool seen_undeleted = false;
     219                        for ( unsigned i = 0; i < candidates.size(); ++i ) {
     220                                int c = winners.empty() ? -1 : candidates[i].cost.compare( winners.front().cost );
     221
     222                                if ( c > 0 ) continue; // skip more expensive than winner
     223
     224                                if ( c < 0 ) {
     225                                        // reset on new cheapest
     226                                        seen_undeleted = ! findDeletedExpr( candidates[i].expr );
     227                                        winners.clear();
     228                                } else /* if ( c == 0 ) */ {
     229                                        if ( findDeletedExpr( candidates[i].expr ) ) {
     230                                                // skip deleted expression if already seen one equivalent-cost not
     231                                                if ( seen_undeleted ) continue;
     232                                        } else if ( ! seen_undeleted ) {
     233                                                // replace list of equivalent-cost deleted expressions with one non-deleted
     234                                                winners.clear();
     235                                                seen_undeleted = true;
     236                                        }
     237                                }
     238
     239                                winners.emplace_back( std::move( candidates[i] ) );
     240                        }
     241
     242                        // promote alternative.cvtCost to .cost
     243                        // xxx - I don't know why this is done, but I'm keeping the behaviour from findMinCost
     244                        for ( Alternative& winner : winners ) {
     245                                winner.cost = winner.cvtCost;
     246                        }
     247
     248                        // produce ambiguous errors, if applicable
     249                        if ( winners.size() != 1 ) {
    198250                                std::ostringstream stream;
    199251                                stream << "Cannot choose between " << winners.size() << " alternatives for " << kindStr << (kindStr != "" ? " " : "") << "expression\n";
     
    204256                        }
    205257
    206                         // there is one unambiguous interpretation - move the expression into the with statement
    207                         Alternative & choice = winners.front();
    208                         if ( findDeletedExpr( choice.expr ) ) {
     258                        // single selected choice
     259                        Alternative& choice = winners.front();
     260
     261                        // fail on only expression deleted
     262                        if ( ! seen_undeleted ) {
    209263                                SemanticError( untyped->location, choice.expr, "Unique best alternative includes deleted identifier in " );
    210264                        }
     265
     266                        // xxx - check for ambiguous expressions
     267
     268                        // output selected choice
    211269                        alt = std::move( choice );
    212270                }
    213271
    214272                /// resolve `untyped` to the expression whose alternative satisfies `pred` with the lowest cost; kindStr is used for providing better error messages
    215                 void findKindExpression(Expression *& untyped, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, bool adjust = false, bool prune = true, bool failFast = true) {
     273                void findKindExpression(Expression *& untyped, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, ResolvMode mode = ResolvMode{}) {
    216274                        if ( ! untyped ) return;
    217275                        Alternative choice;
    218                         findUnfinishedKindExpression( untyped, choice, indexer, kindStr, pred, adjust, prune, failFast );
     276                        findUnfinishedKindExpression( untyped, choice, indexer, kindStr, pred, mode );
    219277                        finishExpr( choice.expr, choice.env, untyped->env );
    220278                        delete untyped;
     
    231289
    232290        // used in resolveTypeof
    233         Expression * resolveInVoidContext( Expression *expr, const SymTab::Indexer &indexer ) {
     291        Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer ) {
    234292                TypeEnvironment env;
    235293                return resolveInVoidContext( expr, indexer, env );
    236294        }
    237295
    238         Expression * resolveInVoidContext( Expression *expr, const SymTab::Indexer &indexer, TypeEnvironment &env ) {
     296        Expression * resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer, TypeEnvironment & env ) {
    239297                // it's a property of the language that a cast expression has either 1 or 0 interpretations; if it has 0
    240298                // interpretations, an exception has already been thrown.
    241299                assertf( expr, "expected a non-null expression." );
    242300
    243                 static CastExpr untyped( nullptr ); // cast to void
    244                 untyped.location = expr->location;
     301                CastExpr * untyped = new CastExpr( expr ); // cast to void
     302                untyped->location = expr->location;
    245303
    246304                // set up and resolve expression cast to void
    247                 untyped.arg = expr;
    248305                Alternative choice;
    249                 findUnfinishedKindExpression( &untyped, choice, indexer, "", standardAlternativeFilter, true );
     306                findUnfinishedKindExpression( untyped, choice, indexer, "", standardAlternativeFilter, ResolvMode::withAdjustment() );
    250307                CastExpr * castExpr = strict_dynamic_cast< CastExpr * >( choice.expr );
     308                assert( castExpr );
    251309                env = std::move( choice.env );
    252310
     
    256314
    257315                // unlink the arg so that it isn't deleted twice at the end of the program
    258                 untyped.arg = nullptr;
     316                untyped->arg = nullptr;
    259317                return ret;
    260318        }
    261319
    262         void findVoidExpression( Expression *& untyped, const SymTab::Indexer &indexer ) {
     320        void findVoidExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {
    263321                resetTyVarRenaming();
    264322                TypeEnvironment env;
     
    269327        }
    270328
    271         void findSingleExpression( Expression *&untyped, const SymTab::Indexer &indexer ) {
     329        void findSingleExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {
    272330                findKindExpression( untyped, indexer, "", standardAlternativeFilter );
    273331        }
     
    288346                        if ( dynamic_cast< EnumInstType * >( type ) ) {
    289347                                return true;
    290                         } else if ( BasicType *bt = dynamic_cast< BasicType * >( type ) ) {
     348                        } else if ( BasicType * bt = dynamic_cast< BasicType * >( type ) ) {
    291349                                return bt->isInteger();
    292350                        } else if ( dynamic_cast< ZeroType* >( type ) != nullptr || dynamic_cast< OneType* >( type ) != nullptr ) {
     
    297355                }
    298356
    299                 void findIntegralExpression( Expression *& untyped, const SymTab::Indexer &indexer ) {
     357                void findIntegralExpression( Expression *& untyped, const SymTab::Indexer & indexer ) {
    300358                        findKindExpression( untyped, indexer, "condition", isIntegralType );
    301359                }
    302360        }
    303361
    304         void Resolver::previsit( ObjectDecl *objectDecl ) {
    305                 Type *new_type = resolveTypeof( objectDecl->get_type(), indexer );
    306                 objectDecl->set_type( new_type );
    307                 // To handle initialization of routine pointers, e.g., int (*fp)(int) = foo(), means that class-variable
    308                 // initContext is changed multiple time because the LHS is analysed twice. The second analysis changes
    309                 // initContext because of a function type can contain object declarations in the return and parameter types. So
    310                 // each value of initContext is retained, so the type on the first analysis is preserved and used for selecting
    311                 // the RHS.
    312                 GuardValue( currentObject );
    313                 currentObject = CurrentObject( objectDecl->get_type() );
    314                 if ( inEnumDecl && dynamic_cast< EnumInstType * >( objectDecl->get_type() ) ) {
    315                         // enumerator initializers should not use the enum type to initialize, since
    316                         // the enum type is still incomplete at this point. Use signed int instead.
    317                         currentObject = CurrentObject( new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );
    318                 }
    319         }
    320 
    321         template< typename PtrType >
    322         void Resolver::handlePtrType( PtrType * type ) {
    323                 if ( type->get_dimension() ) {
    324                         findSingleExpression( type->dimension, SymTab::SizeType->clone(), indexer );
    325                 }
    326         }
    327 
    328         void Resolver::previsit( ArrayType * at ) {
    329                 handlePtrType( at );
    330         }
    331 
    332         void Resolver::previsit( PointerType * pt ) {
    333                 handlePtrType( pt );
    334         }
    335 
    336         void Resolver::previsit( TypeDecl *typeDecl ) {
    337                 if ( typeDecl->get_base() ) {
    338                         Type *new_type = resolveTypeof( typeDecl->get_base(), indexer );
    339                         typeDecl->set_base( new_type );
    340                 } // if
    341         }
    342 
    343         void Resolver::previsit( FunctionDecl *functionDecl ) {
    344 #if 0
    345                 std::cerr << "resolver visiting functiondecl ";
    346                 functionDecl->print( std::cerr );
    347                 std::cerr << std::endl;
    348 #endif
    349                 Type *new_type = resolveTypeof( functionDecl->type, indexer );
    350                 functionDecl->set_type( new_type );
    351                 GuardValue( functionReturn );
    352                 functionReturn = ResolvExpr::extractResultType( functionDecl->type );
    353 
     362
     363        bool isStructOrUnion( const Alternative & alt ) {
     364                Type * t = alt.expr->result->stripReferences();
     365                return dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t );
     366        }
     367
     368        void resolveWithExprs( std::list< Declaration * > & translationUnit ) {
     369                PassVisitor<ResolveWithExprs> resolver;
     370                acceptAll( translationUnit, resolver );
     371        }
     372
     373        void ResolveWithExprs::resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts ) {
     374                for ( Expression *& expr : withExprs )  {
     375                        // only struct- and union-typed expressions are viable candidates
     376                        findKindExpression( expr, indexer, "with statement", isStructOrUnion );
     377
     378                        // if with expression might be impure, create a temporary so that it is evaluated once
     379                        if ( Tuples::maybeImpure( expr ) ) {
     380                                static UniqueName tmpNamer( "_with_tmp_" );
     381                                ObjectDecl * tmp = ObjectDecl::newObject( tmpNamer.newName(), expr->result->clone(), new SingleInit( expr ) );
     382                                expr = new VariableExpr( tmp );
     383                                newStmts.push_back( new DeclStmt( tmp ) );
     384                                if ( InitTweak::isConstructable( tmp->type ) ) {
     385                                        // generate ctor/dtor and resolve them
     386                                        tmp->init = InitTweak::genCtorInit( tmp );
     387                                        tmp->accept( *visitor );
     388                                }
     389                        }
     390                }
     391        }
     392
     393        void ResolveWithExprs::previsit( WithStmt * withStmt ) {
     394                resolveWithExprs( withStmt->exprs, stmtsToAddBefore );
     395        }
     396
     397        void ResolveWithExprs::previsit( FunctionDecl * functionDecl ) {
    354398                {
    355399                        // resolve with-exprs with parameters in scope and add any newly generated declarations to the
     
    367411        }
    368412
    369         void Resolver::postvisit( FunctionDecl *functionDecl ) {
    370                 // default value expressions have an environment which shouldn't be there and trips up later passes.
    371                 // xxx - it might be necessary to somehow keep the information from this environment, but I can't currently
    372                 // see how it's useful.
     413        void Resolver_old::previsit( ObjectDecl * objectDecl ) {
     414                // To handle initialization of routine pointers, e.g., int (*fp)(int) = foo(), means that
     415                // class-variable initContext is changed multiple time because the LHS is analysed twice.
     416                // The second analysis changes initContext because of a function type can contain object
     417                // declarations in the return and parameter types. So each value of initContext is
     418                // retained, so the type on the first analysis is preserved and used for selecting the RHS.
     419                GuardValue( currentObject );
     420                currentObject = CurrentObject( objectDecl->get_type() );
     421                if ( inEnumDecl && dynamic_cast< EnumInstType * >( objectDecl->get_type() ) ) {
     422                        // enumerator initializers should not use the enum type to initialize, since
     423                        // the enum type is still incomplete at this point. Use signed int instead.
     424                        currentObject = CurrentObject( new BasicType( Type::Qualifiers(), BasicType::SignedInt ) );
     425                }
     426        }
     427
     428        template< typename PtrType >
     429        void Resolver_old::handlePtrType( PtrType * type ) {
     430                if ( type->get_dimension() ) {
     431                        findSingleExpression( type->dimension, Validate::SizeType->clone(), indexer );
     432                }
     433        }
     434
     435        void Resolver_old::previsit( ArrayType * at ) {
     436                handlePtrType( at );
     437        }
     438
     439        void Resolver_old::previsit( PointerType * pt ) {
     440                handlePtrType( pt );
     441        }
     442
     443        void Resolver_old::previsit( FunctionDecl * functionDecl ) {
     444#if 0
     445                std::cerr << "resolver visiting functiondecl ";
     446                functionDecl->print( std::cerr );
     447                std::cerr << std::endl;
     448#endif
     449                GuardValue( functionReturn );
     450                functionReturn = ResolvExpr::extractResultType( functionDecl->type );
     451        }
     452
     453        void Resolver_old::postvisit( FunctionDecl * functionDecl ) {
     454                // default value expressions have an environment which shouldn't be there and trips up
     455                // later passes.
     456                // xxx - it might be necessary to somehow keep the information from this environment, but I
     457                // can't currently see how it's useful.
    373458                for ( Declaration * d : functionDecl->type->parameters ) {
    374459                        if ( ObjectDecl * obj = dynamic_cast< ObjectDecl * >( d ) ) {
     
    381466        }
    382467
    383         void Resolver::previsit( EnumDecl * ) {
     468        void Resolver_old::previsit( EnumDecl * ) {
    384469                // in case we decide to allow nested enums
    385470                GuardValue( inEnumDecl );
     
    387472        }
    388473
    389         void Resolver::previsit( StaticAssertDecl * assertDecl ) {
     474        void Resolver_old::previsit( StaticAssertDecl * assertDecl ) {
    390475                findIntegralExpression( assertDecl->condition, indexer );
    391476        }
    392477
    393         void Resolver::previsit( ExprStmt *exprStmt ) {
     478        void Resolver_old::previsit( ExprStmt * exprStmt ) {
    394479                visit_children = false;
    395480                assertf( exprStmt->expr, "ExprStmt has null Expression in resolver" );
     
    397482        }
    398483
    399         void Resolver::previsit( AsmExpr *asmExpr ) {
     484        void Resolver_old::previsit( AsmExpr * asmExpr ) {
    400485                visit_children = false;
    401486                findVoidExpression( asmExpr->operand, indexer );
     
    405490        }
    406491
    407         void Resolver::previsit( AsmStmt *asmStmt ) {
     492        void Resolver_old::previsit( AsmStmt * asmStmt ) {
    408493                visit_children = false;
    409494                acceptAll( asmStmt->get_input(), *visitor );
     
    411496        }
    412497
    413         void Resolver::previsit( IfStmt *ifStmt ) {
     498        void Resolver_old::previsit( IfStmt * ifStmt ) {
    414499                findIntegralExpression( ifStmt->condition, indexer );
    415500        }
    416501
    417         void Resolver::previsit( WhileStmt *whileStmt ) {
     502        void Resolver_old::previsit( WhileStmt * whileStmt ) {
    418503                findIntegralExpression( whileStmt->condition, indexer );
    419504        }
    420505
    421         void Resolver::previsit( ForStmt *forStmt ) {
     506        void Resolver_old::previsit( ForStmt * forStmt ) {
    422507                if ( forStmt->condition ) {
    423508                        findIntegralExpression( forStmt->condition, indexer );
     
    429514        }
    430515
    431         void Resolver::previsit( SwitchStmt *switchStmt ) {
     516        void Resolver_old::previsit( SwitchStmt * switchStmt ) {
    432517                GuardValue( currentObject );
    433518                findIntegralExpression( switchStmt->condition, indexer );
     
    436521        }
    437522
    438         void Resolver::previsit( CaseStmt *caseStmt ) {
     523        void Resolver_old::previsit( CaseStmt * caseStmt ) {
    439524                if ( caseStmt->condition ) {
    440525                        std::list< InitAlternative > initAlts = currentObject.getOptions();
     
    455540        }
    456541
    457         void Resolver::previsit( BranchStmt *branchStmt ) {
     542        void Resolver_old::previsit( BranchStmt * branchStmt ) {
    458543                visit_children = false;
    459544                // must resolve the argument for a computed goto
     
    466551        }
    467552
    468         void Resolver::previsit( ReturnStmt *returnStmt ) {
     553        void Resolver_old::previsit( ReturnStmt * returnStmt ) {
    469554                visit_children = false;
    470555                if ( returnStmt->expr ) {
     
    473558        }
    474559
    475         void Resolver::previsit( ThrowStmt *throwStmt ) {
     560        void Resolver_old::previsit( ThrowStmt * throwStmt ) {
    476561                visit_children = false;
    477562                // TODO: Replace *exception type with &exception type.
    478563                if ( throwStmt->get_expr() ) {
    479                         StructDecl * exception_decl =
    480                                 indexer.lookupStruct( "__cfaabi_ehm__base_exception_t" );
     564                        const StructDecl * exception_decl = indexer.lookupStruct( "__cfaabi_ehm__base_exception_t" );
    481565                        assert( exception_decl );
    482                         Type * exceptType = new PointerType( noQualifiers, new StructInstType( noQualifiers, exception_decl ) );
     566                        Type * exceptType = new PointerType( noQualifiers, new StructInstType( noQualifiers, const_cast<StructDecl *>(exception_decl) ) );
    483567                        findSingleExpression( throwStmt->expr, exceptType, indexer );
    484568                }
    485569        }
    486570
    487         void Resolver::previsit( CatchStmt *catchStmt ) {
     571        void Resolver_old::previsit( CatchStmt * catchStmt ) {
    488572                if ( catchStmt->cond ) {
    489573                        findSingleExpression( catchStmt->cond, new BasicType( noQualifiers, BasicType::Bool ), indexer );
     
    500584        }
    501585
    502         void Resolver::previsit( WaitForStmt * stmt ) {
     586        void Resolver_old::previsit( WaitForStmt * stmt ) {
    503587                visit_children = false;
    504588
     
    582666
    583667                                                        // Make sure we don't widen any existing bindings
    584                                                         for ( auto & i : resultEnv ) {
    585                                                                 i.allowWidening = false;
    586                                                         }
     668                                                        resultEnv.forbidWidening();
    587669
    588670                                                        // Find any unbound type variables
     
    592674                                                        auto param_end = function->parameters.end();
    593675
    594                                                         int n_mutex_arg = 0;
     676                                                        int n_mutex_param = 0;
    595677
    596678                                                        // For every arguments of its set, check if it matches one of the parameter
     
    602684                                                                        // We ran out of parameters but still have arguments
    603685                                                                        // this function doesn't match
    604                                                                         SemanticError( function, toString("candidate function not viable: too many mutex arguments, expected ", n_mutex_arg, "\n" ));
     686                                                                        SemanticError( function, toString("candidate function not viable: too many mutex arguments, expected ", n_mutex_param, "\n" ));
    605687                                                                }
    606688
    607                                                                 n_mutex_arg++;
     689                                                                n_mutex_param++;
    608690
    609691                                                                // Check if the argument matches the parameter type in the current scope
     
    628710                                                        // Check if parameters are missing
    629711                                                        if( advance_to_mutex( param, param_end ) ) {
     712                                                                do {
     713                                                                        n_mutex_param++;
     714                                                                        param++;
     715                                                                } while( advance_to_mutex( param, param_end ) );
     716
    630717                                                                // We ran out of arguments but still have parameters left
    631718                                                                // this function doesn't match
    632                                                                 SemanticError( function, toString("candidate function not viable: too few mutex arguments, expected ", n_mutex_arg, "\n" ));
     719                                                                SemanticError( function, toString("candidate function not viable: too few mutex arguments, expected ", n_mutex_param, "\n" ));
    633720                                                        }
    634721
     
    646733
    647734                                                }
    648                                                 catch( SemanticErrorException &e ) {
     735                                                catch( SemanticErrorException & e ) {
    649736                                                        errors.append( e );
    650737                                                }
    651738                                        }
    652739                                }
    653                                 catch( SemanticErrorException &e ) {
     740                                catch( SemanticErrorException & e ) {
    654741                                        errors.append( e );
    655742                                }
     
    694781        }
    695782
    696         bool isStructOrUnion( const Alternative & alt ) {
    697                 Type * t = alt.expr->result->stripReferences();
    698                 return dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t );
    699         }
    700 
    701         void Resolver::resolveWithExprs( std::list< Expression * > & withExprs, std::list< Statement * > & newStmts ) {
    702                 for ( Expression *& expr : withExprs )  {
    703                         // only struct- and union-typed expressions are viable candidates
    704                         findKindExpression( expr, indexer, "with statement", isStructOrUnion );
    705 
    706                         // if with expression might be impure, create a temporary so that it is evaluated once
    707                         if ( Tuples::maybeImpure( expr ) ) {
    708                                 static UniqueName tmpNamer( "_with_tmp_" );
    709                                 ObjectDecl * tmp = ObjectDecl::newObject( tmpNamer.newName(), expr->result->clone(), new SingleInit( expr ) );
    710                                 expr = new VariableExpr( tmp );
    711                                 newStmts.push_back( new DeclStmt( tmp ) );
    712                                 if ( InitTweak::isConstructable( tmp->type ) ) {
    713                                         // generate ctor/dtor and resolve them
    714                                         tmp->init = InitTweak::genCtorInit( tmp );
    715                                         tmp->accept( *visitor );
    716                                 }
    717                         }
    718                 }
    719         }
    720 
    721         void Resolver::previsit( WithStmt * withStmt ) {
    722                 resolveWithExprs( withStmt->exprs, stmtsToAddBefore );
    723         }
    724 
    725         template< typename T >
    726         bool isCharType( T t ) {
     783        bool isCharType( Type * t ) {
    727784                if ( BasicType * bt = dynamic_cast< BasicType * >( t ) ) {
    728785                        return bt->get_kind() == BasicType::Char || bt->get_kind() == BasicType::SignedChar ||
     
    732789        }
    733790
    734         void Resolver::previsit( SingleInit *singleInit ) {
     791        void Resolver_old::previsit( SingleInit * singleInit ) {
    735792                visit_children = false;
    736793                // resolve initialization using the possibilities as determined by the currentObject cursor
     
    746803                initExpr->expr = nullptr;
    747804                std::swap( initExpr->env, newExpr->env );
    748                 // InitExpr may have inferParams in the case where the expression specializes a function pointer,
    749                 // and newExpr may already have inferParams of its own, so a simple swap is not sufficient.
     805                // InitExpr may have inferParams in the case where the expression specializes a function
     806                // pointer, and newExpr may already have inferParams of its own, so a simple swap is not
     807                // sufficient.
    750808                newExpr->spliceInferParams( initExpr );
    751809                delete initExpr;
    752810
    753                 // get the actual object's type (may not exactly match what comes back from the resolver due to conversions)
     811                // get the actual object's type (may not exactly match what comes back from the resolver
     812                // due to conversions)
    754813                Type * initContext = currentObject.getCurrentType();
    755814
     
    762821                                if ( PointerType * pt = dynamic_cast< PointerType *>( newExpr->get_result() ) ) {
    763822                                        if ( isCharType( pt->get_base() ) ) {
    764                                                 if ( CastExpr *ce = dynamic_cast< CastExpr * >( newExpr ) ) {
    765                                                         // strip cast if we're initializing a char[] with a char *, e.g.  char x[] = "hello";
     823                                                if ( CastExpr * ce = dynamic_cast< CastExpr * >( newExpr ) ) {
     824                                                        // strip cast if we're initializing a char[] with a char *,
     825                                                        // e.g.  char x[] = "hello";
    766826                                                        newExpr = ce->get_arg();
    767827                                                        ce->set_arg( nullptr );
     
    781841        }
    782842
    783         void Resolver::previsit( ListInit * listInit ) {
     843        void Resolver_old::previsit( ListInit * listInit ) {
    784844                visit_children = false;
    785845                // move cursor into brace-enclosed initializer-list
    786846                currentObject.enterListInit();
    787                 // xxx - fix this so that the list isn't copied, iterator should be used to change current element
     847                // xxx - fix this so that the list isn't copied, iterator should be used to change current
     848                // element
    788849                std::list<Designation *> newDesignations;
    789850                for ( auto p : group_iterate(listInit->get_designations(), listInit->get_initializers()) ) {
    790                         // iterate designations and initializers in pairs, moving the cursor to the current designated object and resolving
    791                         // the initializer against that object.
     851                        // iterate designations and initializers in pairs, moving the cursor to the current
     852                        // designated object and resolving the initializer against that object.
    792853                        Designation * des = std::get<0>(p);
    793854                        Initializer * init = std::get<1>(p);
     
    815876
    816877        // ConstructorInit - fall back on C-style initializer
    817         void Resolver::fallbackInit( ConstructorInit * ctorInit ) {
     878        void Resolver_old::fallbackInit( ConstructorInit * ctorInit ) {
    818879                // could not find valid constructor, or found an intrinsic constructor
    819880                // fall back on C-style initializer
    820881                delete ctorInit->get_ctor();
    821                 ctorInit->set_ctor( NULL );
     882                ctorInit->set_ctor( nullptr );
    822883                delete ctorInit->get_dtor();
    823                 ctorInit->set_dtor( NULL );
     884                ctorInit->set_dtor( nullptr );
    824885                maybeAccept( ctorInit->get_init(), *visitor );
    825886        }
     
    828889        void resolveCtorInit( ConstructorInit * ctorInit, const SymTab::Indexer & indexer ) {
    829890                assert( ctorInit );
    830                 PassVisitor<Resolver> resolver( indexer );
     891                PassVisitor<Resolver_old> resolver( indexer );
    831892                ctorInit->accept( resolver );
    832893        }
     
    834895        void resolveStmtExpr( StmtExpr * stmtExpr, const SymTab::Indexer & indexer ) {
    835896                assert( stmtExpr );
    836                 PassVisitor<Resolver> resolver( indexer );
     897                PassVisitor<Resolver_old> resolver( indexer );
    837898                stmtExpr->accept( resolver );
    838899                stmtExpr->computeResult();
     
    840901        }
    841902
    842         void Resolver::previsit( ConstructorInit *ctorInit ) {
     903        void Resolver_old::previsit( ConstructorInit * ctorInit ) {
    843904                visit_children = false;
    844905                // xxx - fallback init has been removed => remove fallbackInit function and remove complexity from FixInit and remove C-init from ConstructorInit
     
    864925
    865926                // xxx - todo -- what about arrays?
    866                 // if ( dtor == NULL && InitTweak::isIntrinsicCallStmt( ctorInit->get_ctor() ) ) {
     927                // if ( dtor == nullptr && InitTweak::isIntrinsicCallStmt( ctorInit->get_ctor() ) ) {
    867928                //      // can reduce the constructor down to a SingleInit using the
    868929                //      // second argument from the ctor call, since
    869930                //      delete ctorInit->get_ctor();
    870                 //      ctorInit->set_ctor( NULL );
     931                //      ctorInit->set_ctor( nullptr );
    871932
    872933                //      Expression * arg =
     
    874935                // }
    875936        }
     937
     938        ///////////////////////////////////////////////////////////////////////////
     939        //
     940        // *** NEW RESOLVER ***
     941        //
     942        ///////////////////////////////////////////////////////////////////////////
     943
     944        namespace {
     945                /// Finds deleted expressions in an expression tree
     946                struct DeleteFinder_new final : public ast::WithShortCircuiting {
     947                        const ast::DeletedExpr * delExpr = nullptr;
     948
     949                        void previsit( const ast::DeletedExpr * expr ) {
     950                                if ( delExpr ) { visit_children = false; }
     951                                else { delExpr = expr; }
     952                        }
     953
     954                        void previsit( const ast::Expr * ) {
     955                                if ( delExpr ) { visit_children = false; }
     956                        }
     957                };
     958        } // anonymous namespace
     959
     960        /// Check if this expression is or includes a deleted expression
     961        const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) {
     962                ast::Pass<DeleteFinder_new> finder;
     963                expr->accept( finder );
     964                return finder.pass.delExpr;
     965        }
     966
     967        namespace {
     968                /// always-accept candidate filter
     969                bool anyCandidate( const Candidate & ) { return true; }
     970
     971                /// Calls the CandidateFinder and finds the single best candidate
     972                CandidateRef findUnfinishedKindExpression(
     973                        const ast::Expr * untyped, const ast::SymbolTable & symtab, const std::string & kind,
     974                        std::function<bool(const Candidate &)> pred = anyCandidate, ResolvMode mode = {}
     975                ) {
     976                        if ( ! untyped ) return nullptr;
     977
     978                        // xxx - this isn't thread-safe, but should work until we parallelize the resolver
     979                        static unsigned recursion_level = 0;
     980
     981                        ++recursion_level;
     982                        ast::TypeEnvironment env;
     983                        CandidateFinder finder{ symtab, env };
     984                        finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );
     985                        --recursion_level;
     986
     987                        // produce a filtered list of candidates
     988                        CandidateList candidates;
     989                        for ( auto & cand : finder.candidates ) {
     990                                if ( pred( *cand ) ) { candidates.emplace_back( cand ); }
     991                        }
     992
     993                        // produce invalid error if no candidates
     994                        if ( candidates.empty() ) {
     995                                SemanticError( untyped,
     996                                        toString( "No reasonable alternatives for ", kind, (kind != "" ? " " : ""),
     997                                        "expression: ") );
     998                        }
     999
     1000                        // search for cheapest candidate
     1001                        CandidateList winners;
     1002                        bool seen_undeleted = false;
     1003                        for ( CandidateRef & cand : candidates ) {
     1004                                int c = winners.empty() ? -1 : cand->cost.compare( winners.front()->cost );
     1005
     1006                                if ( c > 0 ) continue;  // skip more expensive than winner
     1007
     1008                                if ( c < 0 ) {
     1009                                        // reset on new cheapest
     1010                                        seen_undeleted = ! findDeletedExpr( cand->expr );
     1011                                        winners.clear();
     1012                                } else /* if ( c == 0 ) */ {
     1013                                        if ( findDeletedExpr( cand->expr ) ) {
     1014                                                // skip deleted expression if already seen one equivalent-cost not
     1015                                                if ( seen_undeleted ) continue;
     1016                                        } else if ( ! seen_undeleted ) {
     1017                                                // replace list of equivalent-cost deleted expressions with one non-deleted
     1018                                                winners.clear();
     1019                                                seen_undeleted = true;
     1020                                        }
     1021                                }
     1022
     1023                                winners.emplace_back( std::move( cand ) );
     1024                        }
     1025
     1026                        // promote candidate.cvtCost to .cost
     1027                        promoteCvtCost( winners );
     1028
     1029                        // produce ambiguous errors, if applicable
     1030                        if ( winners.size() != 1 ) {
     1031                                std::ostringstream stream;
     1032                                stream << "Cannot choose between " << winners.size() << " alternatives for "
     1033                                        << kind << (kind != "" ? " " : "") << "expression\n";
     1034                                ast::print( stream, untyped );
     1035                                stream << " Alternatives are:\n";
     1036                                print( stream, winners, 1 );
     1037                                SemanticError( untyped->location, stream.str() );
     1038                        }
     1039
     1040                        // single selected choice
     1041                        CandidateRef & choice = winners.front();
     1042
     1043                        // fail on only expression deleted
     1044                        if ( ! seen_undeleted ) {
     1045                                SemanticError( untyped->location, choice->expr.get(), "Unique best alternative "
     1046                                "includes deleted identifier in " );
     1047                        }
     1048
     1049                        return std::move( choice );
     1050                }
     1051
     1052                /// Strips extraneous casts out of an expression
     1053                struct StripCasts_new final {
     1054                        const ast::Expr * postmutate( const ast::CastExpr * castExpr ) {
     1055                                if (
     1056                                        castExpr->isGenerated
     1057                                        && typesCompatible( castExpr->arg->result, castExpr->result )
     1058                                ) {
     1059                                        // generated cast is the same type as its argument, remove it after keeping env
     1060                                        return ast::mutate_field(
     1061                                                castExpr->arg.get(), &ast::Expr::env, castExpr->env );
     1062                                }
     1063                                return castExpr;
     1064                        }
     1065
     1066                        static void strip( ast::ptr< ast::Expr > & expr ) {
     1067                                ast::Pass< StripCasts_new > stripper;
     1068                                expr = expr->accept( stripper );
     1069                        }
     1070                };
     1071
     1072                /// Swaps argument into expression pointer, saving original environment
     1073                void swap_and_save_env( ast::ptr< ast::Expr > & expr, const ast::Expr * newExpr ) {
     1074                        ast::ptr< ast::TypeSubstitution > env = expr->env;
     1075                        expr.set_and_mutate( newExpr )->env = env;
     1076                }
     1077
     1078                /// Removes cast to type of argument (unlike StripCasts, also handles non-generated casts)
     1079                void removeExtraneousCast( ast::ptr<ast::Expr> & expr, const ast::SymbolTable & symtab ) {
     1080                        if ( const ast::CastExpr * castExpr = expr.as< ast::CastExpr >() ) {
     1081                                if ( typesCompatible( castExpr->arg->result, castExpr->result, symtab ) ) {
     1082                                        // cast is to the same type as its argument, remove it
     1083                                        swap_and_save_env( expr, castExpr->arg );
     1084                                }
     1085                        }
     1086                }
     1087
     1088                /// Establish post-resolver invariants for expressions
     1089                void finishExpr(
     1090                        ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env,
     1091                        const ast::TypeSubstitution * oldenv = nullptr
     1092                ) {
     1093                        // set up new type substitution for expression
     1094                        ast::ptr< ast::TypeSubstitution > newenv =
     1095                                 oldenv ? oldenv : new ast::TypeSubstitution{};
     1096                        env.writeToSubstitution( *newenv.get_and_mutate() );
     1097                        expr.get_and_mutate()->env = std::move( newenv );
     1098                        // remove unncecessary casts
     1099                        StripCasts_new::strip( expr );
     1100                }
     1101        } // anonymous namespace
     1102
     1103
     1104        ast::ptr< ast::Expr > resolveInVoidContext(
     1105                const ast::Expr * expr, const ast::SymbolTable & symtab, ast::TypeEnvironment & env
     1106        ) {
     1107                assertf( expr, "expected a non-null expression" );
     1108
     1109                // set up and resolve expression cast to void
     1110                ast::CastExpr * untyped = new ast::CastExpr{ expr };
     1111                CandidateRef choice = findUnfinishedKindExpression(
     1112                        untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() );
     1113
     1114                // a cast expression has either 0 or 1 interpretations (by language rules);
     1115                // if 0, an exception has already been thrown, and this code will not run
     1116                const ast::CastExpr * castExpr = choice->expr.strict_as< ast::CastExpr >();
     1117                env = std::move( choice->env );
     1118
     1119                return castExpr->arg;
     1120        }
     1121
     1122        namespace {
     1123                /// Resolve `untyped` to the expression whose candidate is the best match for a `void`
     1124                /// context.
     1125                ast::ptr< ast::Expr > findVoidExpression(
     1126                        const ast::Expr * untyped, const ast::SymbolTable & symtab
     1127                ) {
     1128                        resetTyVarRenaming();
     1129                        ast::TypeEnvironment env;
     1130                        ast::ptr< ast::Expr > newExpr = resolveInVoidContext( untyped, symtab, env );
     1131                        finishExpr( newExpr, env, untyped->env );
     1132                        return newExpr;
     1133                }
     1134
     1135                /// resolve `untyped` to the expression whose candidate satisfies `pred` with the
     1136                /// lowest cost, returning the resolved version
     1137                ast::ptr< ast::Expr > findKindExpression(
     1138                        const ast::Expr * untyped, const ast::SymbolTable & symtab,
     1139                        std::function<bool(const Candidate &)> pred = anyCandidate,
     1140                        const std::string & kind = "", ResolvMode mode = {}
     1141                ) {
     1142                        if ( ! untyped ) return {};
     1143                        CandidateRef choice =
     1144                                findUnfinishedKindExpression( untyped, symtab, kind, pred, mode );
     1145                        finishExpr( choice->expr, choice->env, untyped->env );
     1146                        return std::move( choice->expr );
     1147                }
     1148
     1149                /// Resolve `untyped` to the single expression whose candidate is the best match
     1150                ast::ptr< ast::Expr > findSingleExpression(
     1151                        const ast::Expr * untyped, const ast::SymbolTable & symtab
     1152                ) {
     1153                        return findKindExpression( untyped, symtab );
     1154                }
     1155        } // anonymous namespace
     1156
     1157                ast::ptr< ast::Expr > findSingleExpression(
     1158                        const ast::Expr * untyped, const ast::Type * type, const ast::SymbolTable & symtab
     1159                ) {
     1160                        assert( untyped && type );
     1161                        ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type };
     1162                        ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, symtab );
     1163                        removeExtraneousCast( newExpr, symtab );
     1164                        return newExpr;
     1165                }
     1166
     1167        namespace {
     1168                /// Predicate for "Candidate has integral type"
     1169                bool hasIntegralType( const Candidate & i ) {
     1170                        const ast::Type * type = i.expr->result;
     1171
     1172                        if ( auto bt = dynamic_cast< const ast::BasicType * >( type ) ) {
     1173                                return bt->isInteger();
     1174                        } else if (
     1175                                dynamic_cast< const ast::EnumInstType * >( type )
     1176                                || dynamic_cast< const ast::ZeroType * >( type )
     1177                                || dynamic_cast< const ast::OneType * >( type )
     1178                        ) {
     1179                                return true;
     1180                        } else return false;
     1181                }
     1182
     1183                /// Resolve `untyped` as an integral expression, returning the resolved version
     1184                ast::ptr< ast::Expr > findIntegralExpression(
     1185                        const ast::Expr * untyped, const ast::SymbolTable & symtab
     1186                ) {
     1187                        return findKindExpression( untyped, symtab, hasIntegralType, "condition" );
     1188                }
     1189
     1190                /// check if a type is a character type
     1191                bool isCharType( const ast::Type * t ) {
     1192                        if ( auto bt = dynamic_cast< const ast::BasicType * >( t ) ) {
     1193                                return bt->kind == ast::BasicType::Char
     1194                                        || bt->kind == ast::BasicType::SignedChar
     1195                                        || bt->kind == ast::BasicType::UnsignedChar;
     1196                        }
     1197                        return false;
     1198                }
     1199
     1200                /// Advance a type itertor to the next mutex parameter
     1201                template<typename Iter>
     1202                inline bool nextMutex( Iter & it, const Iter & end ) {
     1203                        while ( it != end && ! (*it)->get_type()->is_mutex() ) { ++it; }
     1204                        return it != end;
     1205                }
     1206        }
     1207
     1208        class Resolver_new final
     1209        : public ast::WithSymbolTable, public ast::WithGuards,
     1210          public ast::WithVisitorRef<Resolver_new>, public ast::WithShortCircuiting,
     1211          public ast::WithStmtsToAdd<> {
     1212
     1213                ast::ptr< ast::Type > functionReturn = nullptr;
     1214                ast::CurrentObject currentObject;
     1215                bool inEnumDecl = false;
     1216
     1217        public:
     1218                Resolver_new() = default;
     1219                Resolver_new( const ast::SymbolTable & syms ) { symtab = syms; }
     1220
     1221                void previsit( const ast::FunctionDecl * );
     1222                const ast::FunctionDecl * postvisit( const ast::FunctionDecl * );
     1223                void previsit( const ast::ObjectDecl * );
     1224                void previsit( const ast::EnumDecl * );
     1225                const ast::StaticAssertDecl * previsit( const ast::StaticAssertDecl * );
     1226
     1227                const ast::ArrayType * previsit( const ast::ArrayType * );
     1228                const ast::PointerType * previsit( const ast::PointerType * );
     1229
     1230                const ast::ExprStmt *        previsit( const ast::ExprStmt * );
     1231                const ast::AsmExpr *         previsit( const ast::AsmExpr * );
     1232                const ast::AsmStmt *         previsit( const ast::AsmStmt * );
     1233                const ast::IfStmt *          previsit( const ast::IfStmt * );
     1234                const ast::WhileStmt *       previsit( const ast::WhileStmt * );
     1235                const ast::ForStmt *         previsit( const ast::ForStmt * );
     1236                const ast::SwitchStmt *      previsit( const ast::SwitchStmt * );
     1237                const ast::CaseStmt *        previsit( const ast::CaseStmt * );
     1238                const ast::BranchStmt *      previsit( const ast::BranchStmt * );
     1239                const ast::ReturnStmt *      previsit( const ast::ReturnStmt * );
     1240                const ast::ThrowStmt *       previsit( const ast::ThrowStmt * );
     1241                const ast::CatchStmt *       previsit( const ast::CatchStmt * );
     1242                const ast::WaitForStmt *     previsit( const ast::WaitForStmt * );
     1243
     1244                const ast::SingleInit *      previsit( const ast::SingleInit * );
     1245                const ast::ListInit *        previsit( const ast::ListInit * );
     1246                const ast::ConstructorInit * previsit( const ast::ConstructorInit * );
     1247        };
     1248
     1249        void resolve( std::list< ast::ptr<ast::Decl> >& translationUnit ) {
     1250                ast::Pass< Resolver_new > resolver;
     1251                accept_all( translationUnit, resolver );
     1252        }
     1253
     1254        ast::ptr< ast::Init > resolveCtorInit(
     1255                const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab
     1256        ) {
     1257                assert( ctorInit );
     1258                ast::Pass< Resolver_new > resolver{ symtab };
     1259                return ctorInit->accept( resolver );
     1260        }
     1261
     1262        ast::ptr< ast::Expr > resolveStmtExpr(
     1263                const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab
     1264        ) {
     1265                assert( stmtExpr );
     1266                ast::Pass< Resolver_new > resolver{ symtab };
     1267                ast::ptr< ast::Expr > ret = stmtExpr;
     1268                ret = ret->accept( resolver );
     1269                strict_dynamic_cast< ast::StmtExpr * >( ret.get_and_mutate() )->computeResult();
     1270                return ret;
     1271        }
     1272
     1273        void Resolver_new::previsit( const ast::FunctionDecl * functionDecl ) {
     1274                GuardValue( functionReturn );
     1275                functionReturn = extractResultType( functionDecl->type );
     1276        }
     1277
     1278        const ast::FunctionDecl * Resolver_new::postvisit( const ast::FunctionDecl * functionDecl ) {
     1279                // default value expressions have an environment which shouldn't be there and trips up
     1280                // later passes.
     1281                ast::ptr< ast::FunctionDecl > ret = functionDecl;
     1282                for ( unsigned i = 0; i < functionDecl->type->params.size(); ++i ) {
     1283                        const ast::ptr<ast::DeclWithType> & d = functionDecl->type->params[i];
     1284
     1285                        if ( const ast::ObjectDecl * obj = d.as< ast::ObjectDecl >() ) {
     1286                                if ( const ast::SingleInit * init = obj->init.as< ast::SingleInit >() ) {
     1287                                        if ( init->value->env == nullptr ) continue;
     1288                                        // clone initializer minus the initializer environment
     1289                                        ast::chain_mutate( ret )
     1290                                                ( &ast::FunctionDecl::type )
     1291                                                        ( &ast::FunctionType::params )[i]
     1292                                                                ( &ast::ObjectDecl::init )
     1293                                                                        ( &ast::SingleInit::value )->env = nullptr;
     1294
     1295                                        assert( functionDecl != ret.get() || functionDecl->unique() );
     1296                                        assert( ! ret->type->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env );
     1297                                }
     1298                        }
     1299                }
     1300                return ret.get();
     1301        }
     1302
     1303        void Resolver_new::previsit( const ast::ObjectDecl * objectDecl ) {
     1304                // To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()],
     1305                // class-variable `initContext` is changed multiple times because the LHS is analyzed
     1306                // twice. The second analysis changes `initContext` because a function type can contain
     1307                // object declarations in the return and parameter types. Therefore each value of
     1308                // `initContext` is retained so the type on the first analysis is preserved and used for
     1309                // selecting the RHS.
     1310                GuardValue( currentObject );
     1311                currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() };
     1312                if ( inEnumDecl && dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() ) ) {
     1313                        // enumerator initializers should not use the enum type to initialize, since the
     1314                        // enum type is still incomplete at this point. Use `int` instead.
     1315                        currentObject = ast::CurrentObject{
     1316                                objectDecl->location, new ast::BasicType{ ast::BasicType::SignedInt } };
     1317                }
     1318        }
     1319
     1320        void Resolver_new::previsit( const ast::EnumDecl * ) {
     1321                // in case we decide to allow nested enums
     1322                GuardValue( inEnumDecl );
     1323                inEnumDecl = false;
     1324        }
     1325
     1326        const ast::StaticAssertDecl * Resolver_new::previsit(
     1327                const ast::StaticAssertDecl * assertDecl
     1328        ) {
     1329                return ast::mutate_field(
     1330                        assertDecl, &ast::StaticAssertDecl::cond,
     1331                        findIntegralExpression( assertDecl->cond, symtab ) );
     1332        }
     1333
     1334        template< typename PtrType >
     1335        const PtrType * handlePtrType( const PtrType * type, const ast::SymbolTable & symtab ) {
     1336                if ( type->dimension ) {
     1337                        #warning should use new equivalent to Validate::SizeType rather than sizeType here
     1338                        ast::ptr< ast::Type > sizeType = new ast::BasicType{ ast::BasicType::LongUnsignedInt };
     1339                        ast::mutate_field(
     1340                                type, &PtrType::dimension,
     1341                                findSingleExpression( type->dimension, sizeType, symtab ) );
     1342                }
     1343                return type;
     1344        }
     1345
     1346        const ast::ArrayType * Resolver_new::previsit( const ast::ArrayType * at ) {
     1347                return handlePtrType( at, symtab );
     1348        }
     1349
     1350        const ast::PointerType * Resolver_new::previsit( const ast::PointerType * pt ) {
     1351                return handlePtrType( pt, symtab );
     1352        }
     1353
     1354        const ast::ExprStmt * Resolver_new::previsit( const ast::ExprStmt * exprStmt ) {
     1355                visit_children = false;
     1356                assertf( exprStmt->expr, "ExprStmt has null expression in resolver" );
     1357
     1358                return ast::mutate_field(
     1359                        exprStmt, &ast::ExprStmt::expr, findVoidExpression( exprStmt->expr, symtab ) );
     1360        }
     1361
     1362        const ast::AsmExpr * Resolver_new::previsit( const ast::AsmExpr * asmExpr ) {
     1363                visit_children = false;
     1364
     1365                asmExpr = ast::mutate_field(
     1366                        asmExpr, &ast::AsmExpr::operand, findVoidExpression( asmExpr->operand, symtab ) );
     1367
     1368                if ( asmExpr->inout ) {
     1369                        asmExpr = ast::mutate_field(
     1370                                asmExpr, &ast::AsmExpr::inout, findVoidExpression( asmExpr->inout, symtab ) );
     1371                }
     1372
     1373                return asmExpr;
     1374        }
     1375
     1376        const ast::AsmStmt * Resolver_new::previsit( const ast::AsmStmt * asmStmt ) {
     1377                visitor->maybe_accept( asmStmt, &ast::AsmStmt::input );
     1378                visitor->maybe_accept( asmStmt, &ast::AsmStmt::output );
     1379                visit_children = false;
     1380                return asmStmt;
     1381        }
     1382
     1383        const ast::IfStmt * Resolver_new::previsit( const ast::IfStmt * ifStmt ) {
     1384                return ast::mutate_field(
     1385                        ifStmt, &ast::IfStmt::cond, findIntegralExpression( ifStmt->cond, symtab ) );
     1386        }
     1387
     1388        const ast::WhileStmt * Resolver_new::previsit( const ast::WhileStmt * whileStmt ) {
     1389                return ast::mutate_field(
     1390                        whileStmt, &ast::WhileStmt::cond, findIntegralExpression( whileStmt->cond, symtab ) );
     1391        }
     1392
     1393        const ast::ForStmt * Resolver_new::previsit( const ast::ForStmt * forStmt ) {
     1394                if ( forStmt->cond ) {
     1395                        forStmt = ast::mutate_field(
     1396                                forStmt, &ast::ForStmt::cond, findIntegralExpression( forStmt->cond, symtab ) );
     1397                }
     1398
     1399                if ( forStmt->inc ) {
     1400                        forStmt = ast::mutate_field(
     1401                                forStmt, &ast::ForStmt::inc, findVoidExpression( forStmt->inc, symtab ) );
     1402                }
     1403
     1404                return forStmt;
     1405        }
     1406
     1407        const ast::SwitchStmt * Resolver_new::previsit( const ast::SwitchStmt * switchStmt ) {
     1408                GuardValue( currentObject );
     1409                switchStmt = ast::mutate_field(
     1410                        switchStmt, &ast::SwitchStmt::cond,
     1411                        findIntegralExpression( switchStmt->cond, symtab ) );
     1412                currentObject = ast::CurrentObject{ switchStmt->location, switchStmt->cond->result };
     1413                return switchStmt;
     1414        }
     1415
     1416        const ast::CaseStmt * Resolver_new::previsit( const ast::CaseStmt * caseStmt ) {
     1417                if ( caseStmt->cond ) {
     1418                        std::deque< ast::InitAlternative > initAlts = currentObject.getOptions();
     1419                        assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral "
     1420                                "expression." );
     1421
     1422                        ast::ptr< ast::Expr > untyped =
     1423                                new ast::CastExpr{ caseStmt->location, caseStmt->cond, initAlts.front().type };
     1424                        ast::ptr< ast::Expr > newExpr = findSingleExpression( untyped, symtab );
     1425
     1426                        // case condition cannot have a cast in C, so it must be removed here, regardless of
     1427                        // whether it would perform a conversion.
     1428                        if ( const ast::CastExpr * castExpr = newExpr.as< ast::CastExpr >() ) {
     1429                                swap_and_save_env( newExpr, castExpr->arg );
     1430                        }
     1431
     1432                        caseStmt = ast::mutate_field( caseStmt, &ast::CaseStmt::cond, newExpr );
     1433                }
     1434                return caseStmt;
     1435        }
     1436
     1437        const ast::BranchStmt * Resolver_new::previsit( const ast::BranchStmt * branchStmt ) {
     1438                visit_children = false;
     1439                // must resolve the argument of a computed goto
     1440                if ( branchStmt->kind == ast::BranchStmt::Goto && branchStmt->computedTarget ) {
     1441                        // computed goto argument is void*
     1442                        ast::ptr< ast::Type > target = new ast::PointerType{ new ast::VoidType{} };
     1443                        branchStmt = ast::mutate_field(
     1444                                branchStmt, &ast::BranchStmt::computedTarget,
     1445                                findSingleExpression( branchStmt->computedTarget, target, symtab ) );
     1446                }
     1447                return branchStmt;
     1448        }
     1449
     1450        const ast::ReturnStmt * Resolver_new::previsit( const ast::ReturnStmt * returnStmt ) {
     1451                visit_children = false;
     1452                if ( returnStmt->expr ) {
     1453                        returnStmt = ast::mutate_field(
     1454                                returnStmt, &ast::ReturnStmt::expr,
     1455                                findSingleExpression( returnStmt->expr, functionReturn, symtab ) );
     1456                }
     1457                return returnStmt;
     1458        }
     1459
     1460        const ast::ThrowStmt * Resolver_new::previsit( const ast::ThrowStmt * throwStmt ) {
     1461                visit_children = false;
     1462                if ( throwStmt->expr ) {
     1463                        const ast::StructDecl * exceptionDecl =
     1464                                symtab.lookupStruct( "__cfaabi_ehm__base_exception_t" );
     1465                        assert( exceptionDecl );
     1466                        ast::ptr< ast::Type > exceptType =
     1467                                new ast::PointerType{ new ast::StructInstType{ exceptionDecl } };
     1468                        throwStmt = ast::mutate_field(
     1469                                throwStmt, &ast::ThrowStmt::expr,
     1470                                findSingleExpression( throwStmt->expr, exceptType, symtab ) );
     1471                }
     1472                return throwStmt;
     1473        }
     1474
     1475        const ast::CatchStmt * Resolver_new::previsit( const ast::CatchStmt * catchStmt ) {
     1476                if ( catchStmt->cond ) {
     1477                        ast::ptr< ast::Type > boolType = new ast::BasicType{ ast::BasicType::Bool };
     1478                        catchStmt = ast::mutate_field(
     1479                                catchStmt, &ast::CatchStmt::cond,
     1480                                findSingleExpression( catchStmt->cond, boolType, symtab ) );
     1481                }
     1482                return catchStmt;
     1483        }
     1484
     1485        const ast::WaitForStmt * Resolver_new::previsit( const ast::WaitForStmt * stmt ) {
     1486                visit_children = false;
     1487
     1488                // Resolve all clauses first
     1489                for ( unsigned i = 0; i < stmt->clauses.size(); ++i ) {
     1490                        const ast::WaitForStmt::Clause & clause = stmt->clauses[i];
     1491
     1492                        ast::TypeEnvironment env;
     1493                        CandidateFinder funcFinder{ symtab, env };
     1494
     1495                        // Find all candidates for a function in canonical form
     1496                        funcFinder.find( clause.target.func, ResolvMode::withAdjustment() );
     1497
     1498                        if ( funcFinder.candidates.empty() ) {
     1499                                stringstream ss;
     1500                                ss << "Use of undeclared indentifier '";
     1501                                ss << clause.target.func.strict_as< ast::NameExpr >()->name;
     1502                                ss << "' in call to waitfor";
     1503                                SemanticError( stmt->location, ss.str() );
     1504                        }
     1505
     1506                        if ( clause.target.args.empty() ) {
     1507                                SemanticError( stmt->location,
     1508                                        "Waitfor clause must have at least one mutex parameter");
     1509                        }
     1510
     1511                        // Find all alternatives for all arguments in canonical form
     1512                        std::vector< CandidateFinder > argFinders =
     1513                                funcFinder.findSubExprs( clause.target.args );
     1514
     1515                        // List all combinations of arguments
     1516                        std::vector< CandidateList > possibilities;
     1517                        combos( argFinders.begin(), argFinders.end(), back_inserter( possibilities ) );
     1518
     1519                        // For every possible function:
     1520                        // * try matching the arguments to the parameters, not the other way around because
     1521                        //   more arguments than parameters
     1522                        CandidateList funcCandidates;
     1523                        std::vector< CandidateList > argsCandidates;
     1524                        SemanticErrorException errors;
     1525                        for ( CandidateRef & func : funcFinder.candidates ) {
     1526                                try {
     1527                                        auto pointerType = dynamic_cast< const ast::PointerType * >(
     1528                                                func->expr->result->stripReferences() );
     1529                                        if ( ! pointerType ) {
     1530                                                SemanticError( stmt->location, func->expr->result.get(),
     1531                                                        "candidate not viable: not a pointer type\n" );
     1532                                        }
     1533
     1534                                        auto funcType = pointerType->base.as< ast::FunctionType >();
     1535                                        if ( ! funcType ) {
     1536                                                SemanticError( stmt->location, func->expr->result.get(),
     1537                                                        "candidate not viable: not a function type\n" );
     1538                                        }
     1539
     1540                                        {
     1541                                                auto param    = funcType->params.begin();
     1542                                                auto paramEnd = funcType->params.end();
     1543
     1544                                                if( ! nextMutex( param, paramEnd ) ) {
     1545                                                        SemanticError( stmt->location, funcType,
     1546                                                                "candidate function not viable: no mutex parameters\n");
     1547                                                }
     1548                                        }
     1549
     1550                                        CandidateRef func2{ new Candidate{ *func } };
     1551                                        // strip reference from function
     1552                                        func2->expr = referenceToRvalueConversion( func->expr, func2->cost );
     1553
     1554                                        // Each argument must be matched with a parameter of the current candidate
     1555                                        for ( auto & argsList : possibilities ) {
     1556                                                try {
     1557                                                        // Declare data structures needed for resolution
     1558                                                        ast::OpenVarSet open;
     1559                                                        ast::AssertionSet need, have;
     1560                                                        ast::TypeEnvironment resultEnv{ func->env };
     1561                                                        // Add all type variables as open so that those not used in the
     1562                                                        // parameter list are still considered open
     1563                                                        resultEnv.add( funcType->forall );
     1564
     1565                                                        // load type variables from arguments into one shared space
     1566                                                        for ( auto & arg : argsList ) {
     1567                                                                resultEnv.simpleCombine( arg->env );
     1568                                                        }
     1569
     1570                                                        // Make sure we don't widen any existing bindings
     1571                                                        resultEnv.forbidWidening();
     1572
     1573                                                        // Find any unbound type variables
     1574                                                        resultEnv.extractOpenVars( open );
     1575
     1576                                                        auto param = funcType->params.begin();
     1577                                                        auto paramEnd = funcType->params.end();
     1578
     1579                                                        unsigned n_mutex_param = 0;
     1580
     1581                                                        // For every argument of its set, check if it matches one of the
     1582                                                        // parameters. The order is important
     1583                                                        for ( auto & arg : argsList ) {
     1584                                                                // Ignore non-mutex arguments
     1585                                                                if ( ! nextMutex( param, paramEnd ) ) {
     1586                                                                        // We ran out of parameters but still have arguments.
     1587                                                                        // This function doesn't match
     1588                                                                        SemanticError( stmt->location, funcType,
     1589                                                                                toString("candidate function not viable: too many mutex "
     1590                                                                                "arguments, expected ", n_mutex_param, "\n" ) );
     1591                                                                }
     1592
     1593                                                                ++n_mutex_param;
     1594
     1595                                                                // Check if the argument matches the parameter type in the current
     1596                                                                // scope
     1597                                                                ast::ptr< ast::Type > paramType = (*param)->get_type();
     1598                                                                if (
     1599                                                                        ! unify(
     1600                                                                                arg->expr->result, paramType, resultEnv, need, have, open,
     1601                                                                                symtab )
     1602                                                                ) {
     1603                                                                        // Type doesn't match
     1604                                                                        stringstream ss;
     1605                                                                        ss << "candidate function not viable: no known conversion "
     1606                                                                                "from '";
     1607                                                                        ast::print( ss, (*param)->get_type() );
     1608                                                                        ss << "' to '";
     1609                                                                        ast::print( ss, arg->expr->result );
     1610                                                                        ss << "' with env '";
     1611                                                                        ast::print( ss, resultEnv );
     1612                                                                        ss << "'\n";
     1613                                                                        SemanticError( stmt->location, funcType, ss.str() );
     1614                                                                }
     1615
     1616                                                                ++param;
     1617                                                        }
     1618
     1619                                                        // All arguments match!
     1620
     1621                                                        // Check if parameters are missing
     1622                                                        if ( nextMutex( param, paramEnd ) ) {
     1623                                                                do {
     1624                                                                        ++n_mutex_param;
     1625                                                                        ++param;
     1626                                                                } while ( nextMutex( param, paramEnd ) );
     1627
     1628                                                                // We ran out of arguments but still have parameters left; this
     1629                                                                // function doesn't match
     1630                                                                SemanticError( stmt->location, funcType,
     1631                                                                        toString( "candidate function not viable: too few mutex "
     1632                                                                        "arguments, expected ", n_mutex_param, "\n" ) );
     1633                                                        }
     1634
     1635                                                        // All parameters match!
     1636
     1637                                                        // Finish the expressions to tie in proper environments
     1638                                                        finishExpr( func2->expr, resultEnv );
     1639                                                        for ( CandidateRef & arg : argsList ) {
     1640                                                                finishExpr( arg->expr, resultEnv );
     1641                                                        }
     1642
     1643                                                        // This is a match, store it and save it for later
     1644                                                        funcCandidates.emplace_back( std::move( func2 ) );
     1645                                                        argsCandidates.emplace_back( std::move( argsList ) );
     1646
     1647                                                } catch ( SemanticErrorException & e ) {
     1648                                                        errors.append( e );
     1649                                                }
     1650                                        }
     1651                                } catch ( SemanticErrorException & e ) {
     1652                                        errors.append( e );
     1653                                }
     1654                        }
     1655
     1656                        // Make sure correct number of arguments
     1657                        if( funcCandidates.empty() ) {
     1658                                SemanticErrorException top( stmt->location,
     1659                                        "No alternatives for function in call to waitfor" );
     1660                                top.append( errors );
     1661                                throw top;
     1662                        }
     1663
     1664                        if( argsCandidates.empty() ) {
     1665                                SemanticErrorException top( stmt->location,
     1666                                        "No alternatives for arguments in call to waitfor" );
     1667                                top.append( errors );
     1668                                throw top;
     1669                        }
     1670
     1671                        if( funcCandidates.size() > 1 ) {
     1672                                SemanticErrorException top( stmt->location,
     1673                                        "Ambiguous function in call to waitfor" );
     1674                                top.append( errors );
     1675                                throw top;
     1676                        }
     1677                        if( argsCandidates.size() > 1 ) {
     1678                                SemanticErrorException top( stmt->location,
     1679                                        "Ambiguous arguments in call to waitfor" );
     1680                                top.append( errors );
     1681                                throw top;
     1682                        }
     1683                        // TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.
     1684
     1685                        // build new clause
     1686                        ast::WaitForStmt::Clause clause2;
     1687
     1688                        clause2.target.func = funcCandidates.front()->expr;
     1689
     1690                        clause2.target.args.reserve( clause.target.args.size() );
     1691                        for ( auto arg : argsCandidates.front() ) {
     1692                                clause2.target.args.emplace_back( std::move( arg->expr ) );
     1693                        }
     1694
     1695                        // Resolve the conditions as if it were an IfStmt, statements normally
     1696                        clause2.cond = findSingleExpression( clause.cond, symtab );
     1697                        clause2.stmt = clause.stmt->accept( *visitor );
     1698
     1699                        // set results into stmt
     1700                        auto n = mutate( stmt );
     1701                        n->clauses[i] = std::move( clause2 );
     1702                        stmt = n;
     1703                }
     1704
     1705                if ( stmt->timeout.stmt ) {
     1706                        // resolve the timeout as a size_t, the conditions like IfStmt, and stmts normally
     1707                        ast::WaitForStmt::Timeout timeout2;
     1708
     1709                        ast::ptr< ast::Type > target =
     1710                                new ast::BasicType{ ast::BasicType::LongLongUnsignedInt };
     1711                        timeout2.time = findSingleExpression( stmt->timeout.time, target, symtab );
     1712                        timeout2.cond = findSingleExpression( stmt->timeout.cond, symtab );
     1713                        timeout2.stmt = stmt->timeout.stmt->accept( *visitor );
     1714
     1715                        // set results into stmt
     1716                        auto n = mutate( stmt );
     1717                        n->timeout = std::move( timeout2 );
     1718                        stmt = n;
     1719                }
     1720
     1721                if ( stmt->orElse.stmt ) {
     1722                        // resolve the condition like IfStmt, stmts normally
     1723                        ast::WaitForStmt::OrElse orElse2;
     1724
     1725                        orElse2.cond = findSingleExpression( stmt->orElse.cond, symtab );
     1726                        orElse2.stmt = stmt->orElse.stmt->accept( *visitor );
     1727
     1728                        // set results into stmt
     1729                        auto n = mutate( stmt );
     1730                        n->orElse = std::move( orElse2 );
     1731                        stmt = n;
     1732                }
     1733
     1734                return stmt;
     1735        }
     1736
     1737
     1738
     1739        const ast::SingleInit * Resolver_new::previsit( const ast::SingleInit * singleInit ) {
     1740                visit_children = false;
     1741                // resolve initialization using the possibilities as determined by the `currentObject`
     1742                // cursor.
     1743                ast::ptr< ast::Expr > untyped = new ast::UntypedInitExpr{
     1744                        singleInit->location, singleInit->value, currentObject.getOptions() };
     1745                ast::ptr<ast::Expr> newExpr = findSingleExpression( untyped, symtab );
     1746                const ast::InitExpr * initExpr = newExpr.strict_as< ast::InitExpr >();
     1747
     1748                // move cursor to the object that is actually initialized
     1749                currentObject.setNext( initExpr->designation );
     1750
     1751                // discard InitExpr wrapper and retain relevant pieces.
     1752                // `initExpr` may have inferred params in the case where the expression specialized a
     1753                // function pointer, and newExpr may already have inferParams of its own, so a simple
     1754                // swap is not sufficient
     1755                ast::Expr::InferUnion inferred = initExpr->inferred;
     1756                swap_and_save_env( newExpr, initExpr->expr );
     1757                newExpr.get_and_mutate()->inferred.splice( std::move(inferred) );
     1758
     1759                // get the actual object's type (may not exactly match what comes back from the resolver
     1760                // due to conversions)
     1761                const ast::Type * initContext = currentObject.getCurrentType();
     1762
     1763                removeExtraneousCast( newExpr, symtab );
     1764
     1765                // check if actual object's type is char[]
     1766                if ( auto at = dynamic_cast< const ast::ArrayType * >( initContext ) ) {
     1767                        if ( isCharType( at->base ) ) {
     1768                                // check if the resolved type is char*
     1769                                if ( auto pt = newExpr->result.as< ast::PointerType >() ) {
     1770                                        if ( isCharType( pt->base ) ) {
     1771                                                // strip cast if we're initializing a char[] with a char*
     1772                                                // e.g. char x[] = "hello"
     1773                                                if ( auto ce = newExpr.as< ast::CastExpr >() ) {
     1774                                                        swap_and_save_env( newExpr, ce->arg );
     1775                                                }
     1776                                        }
     1777                                }
     1778                        }
     1779                }
     1780
     1781                // move cursor to next object in preparation for next initializer
     1782                currentObject.increment();
     1783
     1784                // set initializer expression to resolved expression
     1785                return ast::mutate_field( singleInit, &ast::SingleInit::value, std::move(newExpr) );
     1786        }
     1787
     1788        const ast::ListInit * Resolver_new::previsit( const ast::ListInit * listInit ) {
     1789                // move cursor into brace-enclosed initializer-list
     1790                currentObject.enterListInit( listInit->location );
     1791
     1792                assert( listInit->designations.size() == listInit->initializers.size() );
     1793                for ( unsigned i = 0; i < listInit->designations.size(); ++i ) {
     1794                        // iterate designations and initializers in pairs, moving the cursor to the current
     1795                        // designated object and resolving the initializer against that object
     1796                        listInit = ast::mutate_field_index(
     1797                                listInit, &ast::ListInit::designations, i,
     1798                                currentObject.findNext( listInit->designations[i] ) );
     1799                        listInit = ast::mutate_field_index(
     1800                                listInit, &ast::ListInit::initializers, i,
     1801                                listInit->initializers[i]->accept( *visitor ) );
     1802                }
     1803
     1804                // move cursor out of brace-enclosed initializer-list
     1805                currentObject.exitListInit();
     1806
     1807                visit_children = false;
     1808                return listInit;
     1809        }
     1810
     1811        const ast::ConstructorInit * Resolver_new::previsit( const ast::ConstructorInit * ctorInit ) {
     1812                visitor->maybe_accept( ctorInit, &ast::ConstructorInit::ctor );
     1813                visitor->maybe_accept( ctorInit, &ast::ConstructorInit::dtor );
     1814
     1815                // found a constructor - can get rid of C-style initializer
     1816                // xxx - Rob suggests this field is dead code
     1817                ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::init, nullptr );
     1818
     1819                // intrinsic single-parameter constructors and destructors do nothing. Since this was
     1820                // implicitly generated, there's no way for it to have side effects, so get rid of it to
     1821                // clean up generated code
     1822                if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) {
     1823                        ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::ctor, nullptr );
     1824                }
     1825                if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->dtor ) ) {
     1826                        ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::dtor, nullptr );
     1827                }
     1828
     1829                return ctorInit;
     1830        }
     1831
    8761832} // namespace ResolvExpr
    8771833
  • src/ResolvExpr/Resolver.h

    r7951100 rb067d9b  
    1010// Created On       : Sun May 17 12:18:34 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:36:57 2017
    13 // Update Count     : 3
     12// Last Modified On : Mon Feb 18 20:40:38 2019
     13// Update Count     : 4
    1414//
    1515
    1616#pragma once
    1717
    18 #include <list>  // for list
     18#include <list>          // for list
     19
     20#include "AST/Node.hpp"  // for ptr
    1921
    2022class ConstructorInit;
     
    2325class StmtExpr;
    2426namespace SymTab {
    25 class Indexer;
    26 }  // namespace SymTab
     27        class Indexer;
     28} // namespace SymTab
     29
     30namespace ast {
     31        class ConstructorInit;
     32        class Decl;
     33        class DeletedExpr;
     34        class Init;
     35        class StmtExpr;
     36        class SymbolTable;
     37        class Type;
     38        class TypeEnvironment;
     39} // namespace ast
    2740
    2841namespace ResolvExpr {
    2942        /// Checks types and binds syntactic constructs to typed representations
    3043        void resolve( std::list< Declaration * > translationUnit );
    31         void resolveDecl( Declaration *, const SymTab::Indexer &indexer );
    32         Expression *resolveInVoidContext( Expression * expr, const SymTab::Indexer &indexer );
    33         void findVoidExpression( Expression *& untyped, const SymTab::Indexer &indexer );
    34         void findSingleExpression( Expression *& untyped, const SymTab::Indexer &indexer );
    35         void findSingleExpression( Expression *& untyped, Type * type, const SymTab::Indexer &indexer );
     44        void resolveDecl( Declaration *, const SymTab::Indexer & indexer );
     45        Expression *resolveInVoidContext( Expression * expr, const SymTab::Indexer & indexer );
     46        void findVoidExpression( Expression *& untyped, const SymTab::Indexer & indexer );
     47        void findSingleExpression( Expression *& untyped, const SymTab::Indexer & indexer );
     48        void findSingleExpression( Expression *& untyped, Type * type, const SymTab::Indexer & indexer );
    3649        void resolveCtorInit( ConstructorInit * ctorInit, const SymTab::Indexer & indexer );
    3750        void resolveStmtExpr( StmtExpr * stmtExpr, const SymTab::Indexer & indexer );
     51        /// Searches expr and returns the first DeletedExpr found, otherwise nullptr
     52        DeletedExpr * findDeletedExpr( Expression * expr );
     53        /// Resolves with-stmts and with-clauses on functions
     54        void resolveWithExprs( std::list< Declaration * > & translationUnit );
     55
     56        /// Checks types and binds syntactic constructs to typed representations
     57        void resolve( std::list< ast::ptr<ast::Decl> >& translationUnit );
     58        /// Searches expr and returns the first DeletedExpr found, otherwise nullptr
     59        const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr );
     60        /// Find the expression candidate that is the unique best match for `untyped` in a `void`
     61        /// context.
     62        ast::ptr< ast::Expr > resolveInVoidContext(
     63                const ast::Expr * expr, const ast::SymbolTable & symtab, ast::TypeEnvironment & env );
     64        /// Resolve `untyped` to the single expression whose candidate is the best match for the
     65        /// given type.
     66        ast::ptr< ast::Expr > findSingleExpression(
     67                const ast::Expr * untyped, const ast::Type * type, const ast::SymbolTable & symtab );
     68        /// Resolves a constructor init expression
     69        ast::ptr< ast::Init > resolveCtorInit(
     70                const ast::ConstructorInit * ctorInit, const ast::SymbolTable & symtab );
     71        /// Resolves a statement expression
     72        ast::ptr< ast::Expr > resolveStmtExpr(
     73                const ast::StmtExpr * stmtExpr, const ast::SymbolTable & symtab );
    3874} // namespace ResolvExpr
    3975
  • src/ResolvExpr/TypeEnvironment.cc

    r7951100 rb067d9b  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 12:19:47 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun May 17 12:23:36 2015
    13 // Update Count     : 3
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Jun 18 14:27:00 2019
     13// Update Count     : 5
    1414//
    1515
     
    1717#include <algorithm>                   // for copy, set_intersection
    1818#include <iterator>                    // for ostream_iterator, insert_iterator
     19#include <memory>                      // for unique_ptr
    1920#include <utility>                     // for pair, move
    2021
     
    2223#include "SynTree/Type.h"              // for Type, FunctionType, Type::Fora...
    2324#include "SynTree/TypeSubstitution.h"  // for TypeSubstitution
     25#include "Tuples/Tuples.h"             // for isTtype
    2426#include "TypeEnvironment.h"
     27#include "typeops.h"                   // for occurs
     28#include "Unify.h"                     // for unifyInexact
    2529
    2630namespace ResolvExpr {
     
    6569        }
    6670
     71        EqvClass::EqvClass( EqvClass &&other )
     72        : vars{std::move(other.vars)}, type{other.type},
     73          allowWidening{std::move(other.allowWidening)}, data{std::move(other.data)} {
     74                  other.type = nullptr;
     75        }
     76
    6777        EqvClass &EqvClass::operator=( const EqvClass &other ) {
    6878                if ( this == &other ) return *this;
     
    7282        }
    7383
     84        EqvClass &EqvClass::operator=( EqvClass &&other ) {
     85                if ( this == &other ) return *this;
     86                delete type;
     87
     88                vars = std::move(other.vars);
     89                type = other.type;
     90                other.type = nullptr;
     91                allowWidening = std::move(other.allowWidening);
     92                data = std::move(other.data);
     93
     94                return *this;
     95        }
     96
    7497        EqvClass::~EqvClass() {
    7598                delete type;
     99        }
     100
     101        void EqvClass::set_type( Type* ty ) {
     102                if ( ty == type ) return;
     103                delete type;
     104                type = ty;
    76105        }
    77106
     
    91120
    92121        const EqvClass* TypeEnvironment::lookup( const std::string &var ) const {
    93                 for ( std::list< EqvClass >::const_iterator i = env.begin(); i != env.end(); ++i ) {
    94                         if ( i->vars.find( var ) != i->vars.end() ) {
    95 ///       std::cout << var << " is in class ";
    96 ///       i->print( std::cout );
    97                                 return &*i;
    98                         }
    99 ///     std::cout << var << " is not in class ";
    100 ///     i->print( std::cout );
     122                for ( ClassList::const_iterator i = env.begin(); i != env.end(); ++i ) {
     123                        if ( i->vars.find( var ) != i->vars.end() ) return &*i;
    101124                } // for
    102125                return nullptr;
     
    109132                        ++next;
    110133                        std::set<std::string> intersection;
    111                         std::set_intersection( i->vars.begin(), i->vars.end(), eqvClass.vars.begin(), eqvClass.vars.end(), 
     134                        std::set_intersection( i->vars.begin(), i->vars.end(), eqvClass.vars.begin(), eqvClass.vars.end(),
    112135                                std::inserter( intersection, intersection.begin() ) );
    113136                        if ( ! intersection.empty() ) { env.erase( i ); }
    114137                        i = next;
    115138                }
    116         }
    117 
    118         void TypeEnvironment::add( const EqvClass &eqvClass ) {
    119                 filterOverlappingClasses( env, eqvClass );
    120                 env.push_back( eqvClass );
    121139        }
    122140
     
    131149                        newClass.vars.insert( (*i)->get_name() );
    132150                        newClass.data = TypeDecl::Data{ (*i) };
    133                         env.push_back( newClass );
     151                        env.push_back( std::move(newClass) );
    134152                } // for
    135153        }
     
    145163                        // transition to TypeSubstitution
    146164                        newClass.data = TypeDecl::Data{ TypeDecl::Dtype, false };
    147                         add( newClass );
     165                        add( std::move(newClass) );
    148166                }
    149167        }
    150168
    151169        void TypeEnvironment::makeSubstitution( TypeSubstitution &sub ) const {
    152                 for ( std::list< EqvClass >::const_iterator theClass = env.begin(); theClass != env.end(); ++theClass ) {
     170                for ( ClassList::const_iterator theClass = env.begin(); theClass != env.end(); ++theClass ) {
    153171                        for ( std::set< std::string >::const_iterator theVar = theClass->vars.begin(); theVar != theClass->vars.end(); ++theVar ) {
    154 ///       std::cerr << "adding " << *theVar;
    155172                                if ( theClass->type ) {
    156 ///         std::cerr << " bound to ";
    157 ///         theClass->type->print( std::cerr );
    158 ///         std::cerr << std::endl;
    159173                                        sub.add( *theVar, theClass->type );
    160174                                } else if ( theVar != theClass->vars.begin() ) {
    161175                                        TypeInstType *newTypeInst = new TypeInstType( Type::Qualifiers(), *theClass->vars.begin(), theClass->data.kind == TypeDecl::Ftype );
    162 ///         std::cerr << " bound to variable " << *theClass->vars.begin() << std::endl;
    163176                                        sub.add( *theVar, newTypeInst );
    164177                                        delete newTypeInst;
     
    166179                        } // for
    167180                } // for
    168 ///   std::cerr << "input env is:" << std::endl;
    169 ///   print( std::cerr, 8 );
    170 ///   std::cerr << "sub is:" << std::endl;
    171 ///   sub.print( std::cerr, 8 );
    172181                sub.normalize();
    173182        }
     
    179188        }
    180189
    181         std::list< EqvClass >::iterator TypeEnvironment::internal_lookup( const std::string &var ) {
    182                 for ( std::list< EqvClass >::iterator i = env.begin(); i != env.end(); ++i ) {
    183                         if ( i->vars.find( var ) == i->vars.end() ) {
    184                                 return i;
    185                         } // if
     190        TypeEnvironment::ClassList::iterator TypeEnvironment::internal_lookup( const std::string &var ) {
     191                for ( ClassList::iterator i = env.begin(); i != env.end(); ++i ) {
     192                        if ( i->vars.count( var ) ) return i;
    186193                } // for
    187194                return env.end();
     
    192199        }
    193200
    194         void TypeEnvironment::combine( const TypeEnvironment &second, Type *(*combineFunc)( Type*, Type* ) ) {
    195                 TypeEnvironment secondCopy( second );
    196                 for ( std::list< EqvClass >::iterator firstClass = env.begin(); firstClass != env.end(); ++firstClass ) {
    197                         EqvClass &newClass = *firstClass;
    198                         std::set< std::string > newVars;
    199                         for ( std::set< std::string >::const_iterator var = firstClass->vars.begin(); var != firstClass->vars.end(); ++var ) {
    200                                 std::list< EqvClass >::iterator secondClass = secondCopy.internal_lookup( *var );
    201                                 if ( secondClass != secondCopy.env.end() ) {
    202                                         newVars.insert( secondClass->vars.begin(), secondClass->vars.end() );
    203                                         if ( secondClass->type ) {
    204                                                 if ( newClass.type ) {
    205                                                         Type *newType = combineFunc( newClass.type, secondClass->type );
    206                                                         delete newClass.type;
    207                                                         newClass.type = newType;
    208                                                         newClass.allowWidening = newClass.allowWidening && secondClass->allowWidening;
    209                                                 } else {
    210                                                         newClass.type = secondClass->type->clone();
    211                                                         newClass.allowWidening = secondClass->allowWidening;
    212                                                 } // if
    213                                         } // if
    214                                         secondCopy.env.erase( secondClass );
    215                                 } // if
    216                         } // for
    217                         newClass.vars.insert( newVars.begin(), newVars.end() );
    218                 } // for
    219                 for ( std::list< EqvClass >::iterator secondClass = secondCopy.env.begin(); secondClass != secondCopy.env.end(); ++secondClass ) {
    220                         env.push_back( *secondClass );
    221                 } // for
     201        // xxx -- this should maybe be worrying about iterator invalidation (see resolv-proto)
     202        bool TypeEnvironment::mergeBound( EqvClass& to, const EqvClass& from, OpenVarSet& openVars, const SymTab::Indexer& indexer ) {
     203                if ( from.type ) {
     204                        if ( to.type ) {
     205                                // attempt to unify bound types
     206                                std::unique_ptr<Type> toType{ to.type->clone() }, fromType{ from.type->clone() };
     207                                WidenMode widen{ to.allowWidening, from.allowWidening };
     208                                Type* common = nullptr;
     209                                AssertionSet need, have;
     210                                if ( unifyInexact( toType.get(), fromType.get(), *this, need, have, openVars, widen, indexer, common ) ) {
     211                                        // unifies, set common type if necessary
     212                                        if ( common ) {
     213                                                common->get_qualifiers() = Type::Qualifiers{};
     214                                                to.set_type( common );
     215                                        }
     216                                } else return false; // cannot unify
     217                        } else {
     218                                to.type = from.type->clone();
     219                        }
     220                }
     221
     222                // unify widening if matches
     223                to.allowWidening &= from.allowWidening;
     224                return true;
     225        }
     226
     227        // xxx -- this should maybe be worrying about iterator invalidation (see resolv-proto)
     228        bool TypeEnvironment::mergeClasses( TypeEnvironment::ClassList::iterator to, TypeEnvironment::ClassList::iterator from, OpenVarSet& openVars, const SymTab::Indexer& indexer ) {
     229                EqvClass& r = *to;
     230                EqvClass& s = *from;
     231
     232                // ensure bounds match
     233                if ( ! mergeBound( r, s, openVars, indexer ) ) return false;
     234
     235                // check safely bindable
     236                if ( r.type && occursIn( r.type, s.vars.begin(), s.vars.end(), *this ) ) return false;
     237               
     238                // merge classes in
     239                r.vars.insert( s.vars.begin(), s.vars.end() );
     240                r.allowWidening &= s.allowWidening;
     241                env.erase( from );
     242
     243                return true;
     244        }
     245
     246        bool TypeEnvironment::combine( const TypeEnvironment& o, OpenVarSet& openVars, const SymTab::Indexer& indexer ) {
     247                // short-circuit easy cases
     248                if ( o.isEmpty() ) return true;
     249                if ( isEmpty() ) {
     250                        simpleCombine( o );
     251                        return true;
     252                }
     253
     254                // merge classes
     255                for ( auto ct = o.env.begin(); ct != o.env.end(); ++ct ) {
     256                        const EqvClass& c = *ct;
     257
     258                        // typeclass in local environment bound to c
     259                        auto rt = env.end();
     260
     261                        // look for first existing bound variable
     262                        auto vt = c.vars.begin();
     263                        for ( ; vt != c.vars.end(); ++vt ) {
     264                                rt = internal_lookup( *vt );
     265                                if ( rt != env.end() ) break;
     266                        }
     267
     268                        if ( rt != env.end() ) {  // c needs to be merged into *rt
     269                                EqvClass& r = *rt;
     270                                // merge bindings
     271                                if ( ! mergeBound( r, c, openVars, indexer ) ) return false;
     272                                // merge previous unbound variables into this class, checking occurs if needed
     273                                if ( r.type ) for ( auto ut = c.vars.begin(); ut != vt; ++ut ) {
     274                                        if ( occurs( r.type, *ut, *this ) ) return false;
     275                                        r.vars.insert( *ut );
     276                                } else { r.vars.insert( c.vars.begin(), vt ); }
     277                                // merge subsequent variables into this class (skipping *vt, already there)
     278                                while ( ++vt != c.vars.end() ) {
     279                                        auto st = internal_lookup( *vt );
     280                                        if ( st == env.end() ) {
     281                                                // unbound, safe to add if passes occurs
     282                                                if ( r.type && occurs( r.type, *vt, *this ) ) return false;
     283                                                r.vars.insert( *vt );
     284                                        } else if ( st != rt ) {
     285                                                // bound, but not to the same class
     286                                                if ( ! mergeClasses( rt, st, openVars, indexer ) ) return false;
     287                                        }   // ignore bound into the same class
     288                                }
     289                        } else {  // no variables in c bound; just copy up
     290                                env.push_back( c );
     291                        }
     292                }
     293
     294                // merged all classes
     295                return true;
    222296        }
    223297
    224298        void TypeEnvironment::extractOpenVars( OpenVarSet &openVars ) const {
    225                 for ( std::list< EqvClass >::const_iterator eqvClass = env.begin(); eqvClass != env.end(); ++eqvClass ) {
     299                for ( ClassList::const_iterator eqvClass = env.begin(); eqvClass != env.end(); ++eqvClass ) {
    226300                        for ( std::set< std::string >::const_iterator var = eqvClass->vars.begin(); var != eqvClass->vars.end(); ++var ) {
    227301                                openVars[ *var ] = eqvClass->data;
     
    241315        }
    242316
     317        bool isFtype( const Type * type ) {
     318                if ( dynamic_cast< const FunctionType * >( type ) ) {
     319                        return true;
     320                } else if ( const TypeInstType *typeInst = dynamic_cast< const TypeInstType * >( type ) ) {
     321                        return typeInst->get_isFtype();
     322                } // if
     323                return false;
     324        }
     325
     326        bool tyVarCompatible( const TypeDecl::Data & data, const Type * type ) {
     327                switch ( data.kind ) {
     328                  case TypeDecl::Dtype:
     329                        // to bind to an object type variable, the type must not be a function type.
     330                        // if the type variable is specified to be a complete type then the incoming
     331                        // type must also be complete
     332                        // xxx - should this also check that type is not a tuple type and that it's not a ttype?
     333                        return ! isFtype( type ) && (! data.isComplete || type->isComplete() );
     334                  case TypeDecl::Ftype:
     335                        return isFtype( type );
     336                  case TypeDecl::Ttype:
     337                        // ttype unifies with any tuple type
     338                        return dynamic_cast< const TupleType * >( type ) || Tuples::isTtype( type );
     339                  default:
     340                        assertf(false, "Unhandled tyvar kind: %d", data.kind);
     341                } // switch
     342                return false;
     343        }
     344
     345        bool TypeEnvironment::bindVar( const TypeInstType *typeInst, Type *bindTo, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ) {
     346
     347                // remove references from other, so that type variables can only bind to value types
     348                bindTo = bindTo->stripReferences();
     349                OpenVarSet::const_iterator tyvar = openVars.find( typeInst->get_name() );
     350                assert( tyvar != openVars.end() );
     351                if ( ! tyVarCompatible( tyvar->second, bindTo ) ) {
     352                        return false;
     353                } // if
     354                if ( occurs( bindTo, typeInst->get_name(), *this ) ) {
     355                        return false;
     356                } // if
     357                auto curClass = internal_lookup( typeInst->get_name() );
     358                if ( curClass != env.end() ) {
     359                        if ( curClass->type ) {
     360                                Type *common = 0;
     361                                // attempt to unify equivalence class type (which has qualifiers stripped, so they must be restored) with the type to bind to
     362                                std::unique_ptr< Type > newType( curClass->type->clone() );
     363                                newType->tq = typeInst->tq;
     364                                if ( unifyInexact( newType.get(), bindTo, *this, need, have, openVars, widen & WidenMode( curClass->allowWidening, true ), indexer, common ) ) {
     365                                        if ( common ) {
     366                                                common->get_qualifiers() = Type::Qualifiers{};
     367                                                curClass->set_type( common );
     368                                        } // if
     369                                } else return false;
     370                        } else {
     371                                Type* newType = bindTo->clone();
     372                                newType->get_qualifiers() = Type::Qualifiers{};
     373                                curClass->set_type( newType );
     374                                curClass->allowWidening = widen.first && widen.second;
     375                        } // if
     376                } else {
     377                        EqvClass newClass;
     378                        newClass.vars.insert( typeInst->get_name() );
     379                        newClass.type = bindTo->clone();
     380                        newClass.type->get_qualifiers() = Type::Qualifiers();
     381                        newClass.allowWidening = widen.first && widen.second;
     382                        newClass.data = data;
     383                        env.push_back( std::move(newClass) );
     384                } // if
     385                return true;
     386        }
     387
     388        bool TypeEnvironment::bindVarToVar( const TypeInstType * var1, const TypeInstType * var2,
     389                        TypeDecl::Data && data, AssertionSet &need, AssertionSet &have,
     390                        const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ) {
     391
     392                auto class1 = internal_lookup( var1->get_name() );
     393                auto class2 = internal_lookup( var2->get_name() );
     394
     395                // exit early if variables already bound together
     396                if ( class1 != env.end() && class1 == class2 ) {
     397                        class1->allowWidening &= widen;
     398                        return true;
     399                }
     400
     401                bool widen1 = false, widen2 = false;
     402                const Type *type1 = nullptr, *type2 = nullptr;
     403
     404                // check for existing bindings, perform occurs check
     405                if ( class1 != env.end() ) {
     406                        if ( class1->type ) {
     407                                if ( occurs( class1->type, var2->get_name(), *this ) ) return false;
     408                                type1 = class1->type;
     409                        } // if
     410                        widen1 = widen.first && class1->allowWidening;
     411                } // if
     412                if ( class2 != env.end() ) {
     413                        if ( class2->type ) {
     414                                if ( occurs( class2->type, var1->get_name(), *this ) ) return false;
     415                                type2 = class2->type;
     416                        } // if
     417                        widen2 = widen.second && class2->allowWidening;
     418                } // if
     419
     420                if ( type1 && type2 ) {
     421                        // both classes bound, merge if bound types can be unified
     422                        std::unique_ptr<Type> newType1{ type1->clone() }, newType2{ type2->clone() };
     423                        WidenMode newWidenMode{ widen1, widen2 };
     424                        Type *common = 0;
     425                        if ( unifyInexact( newType1.get(), newType2.get(), *this, need, have, openVars, newWidenMode, indexer, common ) ) {
     426                                class1->vars.insert( class2->vars.begin(), class2->vars.end() );
     427                                class1->allowWidening = widen1 && widen2;
     428                                if ( common ) {
     429                                        common->get_qualifiers() = Type::Qualifiers{};
     430                                        class1->set_type( common );
     431                                }
     432                                class1->data.isComplete |= data.isComplete;
     433                                env.erase( class2 );
     434                        } else return false;
     435                } else if ( class1 != env.end() && class2 != env.end() ) {
     436                        // both classes exist, at least one unbound, merge unconditionally
     437                        if ( type1 ) {
     438                                class1->vars.insert( class2->vars.begin(), class2->vars.end() );
     439                                class1->allowWidening = widen1;
     440                                class1->data.isComplete |= data.isComplete;
     441                                env.erase( class2 );
     442                        } else {
     443                                class2->vars.insert( class1->vars.begin(), class1->vars.end() );
     444                                class2->allowWidening = widen2;
     445                                class2->data.isComplete |= data.isComplete;
     446                                env.erase( class1 );
     447                        } // if
     448                } else if ( class1 != env.end() ) {
     449                        // var2 unbound, add to class1
     450                        class1->vars.insert( var2->get_name() );
     451                        class1->allowWidening = widen1;
     452                        class1->data.isComplete |= data.isComplete;
     453                } else if ( class2 != env.end() ) {
     454                        // var1 unbound, add to class2
     455                        class2->vars.insert( var1->get_name() );
     456                        class2->allowWidening = widen2;
     457                        class2->data.isComplete |= data.isComplete;
     458                } else {
     459                        // neither var bound, create new class
     460                        EqvClass newClass;
     461                        newClass.vars.insert( var1->get_name() );
     462                        newClass.vars.insert( var2->get_name() );
     463                        newClass.allowWidening = widen1 && widen2;
     464                        newClass.data = data;
     465                        env.push_back( std::move(newClass) );
     466                } // if
     467                return true;
     468        }
     469
     470        void TypeEnvironment::forbidWidening() {
     471                for ( EqvClass& c : env ) c.allowWidening = false;
     472        }
     473
    243474        std::ostream & operator<<( std::ostream & out, const TypeEnvironment & env ) {
    244475                env.print( out );
  • src/ResolvExpr/TypeEnvironment.h

    r7951100 rb067d9b  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 12:24:58 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:35:45 2017
    13 // Update Count     : 3
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Jul 19 17:00:10 2019
     13// Update Count     : 10
    1414//
    1515
     
    1818#include <iostream>                    // for ostream
    1919#include <list>                        // for list, list<>::iterator, list<>...
    20 #include <map>                         // for map, map<>::value_compare
    21 #include <set>                         // for set
     20#include <map>                                             // for map, map<>::value_compare
     21#include <unordered_map>
     22#include <set>                                             // for set
    2223#include <string>                      // for string
     24#include <utility>                     // for move, swap
     25
     26#include "WidenMode.h"                 // for WidenMode
    2327
    2428#include "SynTree/Declaration.h"       // for TypeDecl::Data, DeclarationWit...
     
    3640        // declarations.
    3741        //
    38         // I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this comparator.
     42        // I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this
     43        // comparator.
    3944        //
    4045        // Note: since this compares pointers for position, minor changes in the source file that affect
    4146        // memory layout can alter compilation time in unpredictable ways. For example, the placement
    4247        // of a line directive can reorder type pointers with respect to each other so that assertions
    43         // are seen in different orders, causing a potentially different number of unification calls when
    44         // resolving assertions. I've seen a TU go from 36 seconds to 27 seconds by reordering line directives
    45         // alone, so it would be nice to fix this comparison so that assertions compare more consistently.
    46         // I've tried to modify this to compare on mangle name instead of type as the second comparator, but
    47         // this causes some assertions to never be recorded. More investigation is needed.
     48        // are seen in different orders, causing a potentially different number of unification calls
     49        // when resolving assertions. I've seen a TU go from 36 seconds to 27 seconds by reordering
     50        // line directives alone, so it would be nice to fix this comparison so that assertions compare
     51        // more consistently. I've tried to modify this to compare on mangle name instead of type as
     52        // the second comparator, but this causes some assertions to never be recorded. More
     53        // investigation is needed.
    4854        struct AssertCompare {
    49                 bool operator()( DeclarationWithType * d1, DeclarationWithType * d2 ) const {
     55                bool operator()( const DeclarationWithType * d1, const DeclarationWithType * d2 ) const {
    5056                        int cmp = d1->get_name().compare( d2->get_name() );
    5157                        return cmp < 0 ||
     
    5460        };
    5561        struct AssertionSetValue {
    56                 bool isUsed;
    57                 // chain of Unique IDs of the assertion declarations. The first ID in the chain is the ID of an assertion on the current type,
    58                 // with each successive ID being the ID of an assertion pulled in by the previous ID. The last ID in the chain is
    59                 // the ID of the assertion that pulled in the current assertion.
    60                 std::list< UniqueId > idChain;
     62                bool isUsed;        ///< True if assertion needs to be resolved
     63                UniqueId resnSlot;  ///< ID of slot assertion belongs to
     64
     65                AssertionSetValue() : isUsed(false), resnSlot(0) {}
    6166        };
    62         typedef std::map< DeclarationWithType*, AssertionSetValue, AssertCompare > AssertionSet;
    63         typedef std::map< std::string, TypeDecl::Data > OpenVarSet;
     67        typedef std::map< const DeclarationWithType *, AssertionSetValue, AssertCompare > AssertionSet;
     68        typedef std::unordered_map< std::string, TypeDecl::Data > OpenVarSet;
     69
     70        /// merges one set of open vars into another
     71        static inline void mergeOpenVars( OpenVarSet& dst, const OpenVarSet& src ) {
     72                for ( const auto& entry : src ) { dst[ entry.first ] = entry.second; }
     73        }
    6474
    6575        void printAssertionSet( const AssertionSet &, std::ostream &, int indent = 0 );
     
    6878        struct EqvClass {
    6979                std::set< std::string > vars;
    70                 Type *type;
     80                Type * type;
    7181                bool allowWidening;
    7282                TypeDecl::Data data;
     
    7787                EqvClass( const EqvClass &other );
    7888                EqvClass( const EqvClass &other, const Type *ty );
     89                EqvClass( EqvClass &&other );
    7990                EqvClass &operator=( const EqvClass &other );
     91                EqvClass &operator=( EqvClass &&other );
    8092                ~EqvClass();
    8193                void print( std::ostream &os, Indenter indent = {} ) const;
     94
     95                /// Takes ownership of `ty`, freeing old `type`
     96                void set_type(Type* ty);
    8297        };
    8398
    8499        class TypeEnvironment {
     100                using ClassList = std::list< EqvClass >;
    85101          public:
    86102                const EqvClass* lookup( const std::string &var ) const;
    87                 void add( const EqvClass &eqvClass );
     103          private:
    88104                void add( EqvClass &&eqvClass  );
     105          public:
    89106                void add( const Type::ForallList &tyDecls );
    90107                void add( const TypeSubstitution & sub );
     
    94111                bool isEmpty() const { return env.empty(); }
    95112                void print( std::ostream &os, Indenter indent = {} ) const;
    96                 void combine( const TypeEnvironment &second, Type *(*combineFunc)( Type*, Type* ) );
     113
     114                /// Simply concatenate the second environment onto this one; no safety checks performed
    97115                void simpleCombine( const TypeEnvironment &second );
     116
     117          private:
     118                /// Unifies the type bound of to with the type bound of from, returning false if fails
     119                bool mergeBound( EqvClass& to, const EqvClass& from, OpenVarSet& openVars, const SymTab::Indexer& indexer );
     120
     121                /// Merges two type classes from local environment, returning false if fails
     122                bool mergeClasses( ClassList::iterator to, ClassList::iterator from, OpenVarSet& openVars, const SymTab::Indexer& indexer );
     123
     124          public:
     125                /// Merges the second environment with this one, checking compatibility.
     126                /// Returns false if fails, but does NOT roll back partial changes.
     127                bool combine( const TypeEnvironment& second, OpenVarSet& openVars, const SymTab::Indexer& indexer );
     128
    98129                void extractOpenVars( OpenVarSet &openVars ) const;
    99130                TypeEnvironment *clone() const { return new TypeEnvironment( *this ); }
     
    103134                void addActual( const TypeEnvironment& actualEnv, OpenVarSet& openVars );
    104135
    105                 typedef std::list< EqvClass >::iterator iterator;
    106                 iterator begin() { return env.begin(); }
    107                 iterator end() { return env.end(); }
    108                 typedef std::list< EqvClass >::const_iterator const_iterator;
    109                 const_iterator begin() const { return env.begin(); }
    110                 const_iterator end() const { return env.end(); }
     136                /// Binds the type class represented by `typeInst` to the type `bindTo`; will add
     137                /// the class if needed. Returns false on failure.
     138                bool bindVar( const TypeInstType * typeInst, Type * bindTo, const TypeDecl::Data & data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );
     139
     140                /// Binds the type classes represented by `var1` and `var2` together; will add
     141                /// one or both classes if needed. Returns false on failure.
     142                bool bindVarToVar( const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, AssertionSet &need, AssertionSet &have, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );
     143
     144                /// Disallows widening for all bindings in the environment
     145                void forbidWidening();
     146
     147                using iterator = ClassList::const_iterator;
     148                iterator begin() const { return env.begin(); }
     149                iterator end() const { return env.end(); }
     150
    111151          private:
    112                 std::list< EqvClass > env;
    113                 std::list< EqvClass >::iterator internal_lookup( const std::string &var );
     152                ClassList env;
     153
     154                ClassList::iterator internal_lookup( const std::string &var );
    114155        };
    115156
  • src/ResolvExpr/Unify.cc

    r7951100 rb067d9b  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 12:27:10 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Mar 16 16:22:54 2017
    13 // Update Count     : 42
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Sep  4 10:00:00 2019
     13// Update Count     : 44
    1414//
    1515
    16 #include <cassert>                // for assertf, assert
    17 #include <iterator>               // for back_insert_iterator, back_inserter
    18 #include <map>                    // for _Rb_tree_const_iterator, _Rb_tree_i...
    19 #include <memory>                 // for unique_ptr
    20 #include <set>                    // for set
    21 #include <string>                 // for string, operator==, operator!=, bas...
    22 #include <utility>                // for pair, move
    23 
    24 #include "Common/PassVisitor.h"   // for PassVisitor
    25 #include "FindOpenVars.h"         // for findOpenVars
    26 #include "Parser/LinkageSpec.h"   // for C
    27 #include "SynTree/Constant.h"     // for Constant
    28 #include "SynTree/Declaration.h"  // for TypeDecl, TypeDecl::Data, Declarati...
    29 #include "SynTree/Expression.h"   // for TypeExpr, Expression, ConstantExpr
    30 #include "SynTree/Mutator.h"      // for Mutator
    31 #include "SynTree/Type.h"         // for Type, TypeInstType, FunctionType
    32 #include "SynTree/Visitor.h"      // for Visitor
    33 #include "Tuples/Tuples.h"        // for isTtype
    34 #include "TypeEnvironment.h"      // for EqvClass, AssertionSet, OpenVarSet
    3516#include "Unify.h"
    36 #include "typeops.h"              // for flatten, occurs, commonType
     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/Decl.hpp"
     28#include "AST/Node.hpp"
     29#include "AST/Pass.hpp"
     30#include "AST/Type.hpp"
     31#include "AST/TypeEnvironment.hpp"
     32#include "Common/PassVisitor.h"     // for PassVisitor
     33#include "FindOpenVars.h"           // for findOpenVars
     34#include "Parser/LinkageSpec.h"     // for C
     35#include "SynTree/Constant.h"       // for Constant
     36#include "SynTree/Declaration.h"    // for TypeDecl, TypeDecl::Data, Declarati...
     37#include "SynTree/Expression.h"     // for TypeExpr, Expression, ConstantExpr
     38#include "SynTree/Mutator.h"        // for Mutator
     39#include "SynTree/Type.h"           // for Type, TypeInstType, FunctionType
     40#include "SynTree/Visitor.h"        // for Visitor
     41#include "Tuples/Tuples.h"          // for isTtype
     42#include "TypeEnvironment.h"        // for EqvClass, AssertionSet, OpenVarSet
     43#include "typeops.h"                // for flatten, occurs, commonType
     44
     45namespace ast {
     46        class SymbolTable;
     47}
    3748
    3849namespace SymTab {
     
    4455namespace ResolvExpr {
    4556
    46         struct Unify : public WithShortCircuiting {
    47                 Unify( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );
     57        struct Unify_old : public WithShortCircuiting {
     58                Unify_old( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );
    4859
    4960                bool get_result() const { return result; }
     
    7788                AssertionSet &haveAssertions;
    7889                const OpenVarSet &openVars;
    79                 WidenMode widenMode;
     90                WidenMode widen;
    8091                const SymTab::Indexer &indexer;
    8192        };
     
    8394        /// Attempts an inexact unification of type1 and type2.
    8495        /// Returns false if no such unification; if the types can be unified, sets common (unless they unify exactly and have identical type qualifiers)
    85         bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer, Type *&common );
    86         bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );
    87 
    88         bool typesCompatible( Type *first, Type *second, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
     96        bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common );
     97        bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer );
     98
     99        bool unifyExact(
     100                const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
     101                ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
     102                WidenMode widen, const ast::SymbolTable & symtab );
     103
     104        bool typesCompatible( const Type * first, const Type * second, const SymTab::Indexer & indexer, const TypeEnvironment & env ) {
    89105                TypeEnvironment newEnv;
    90106                OpenVarSet openVars, closedVars; // added closedVars
    91107                AssertionSet needAssertions, haveAssertions;
    92                 Type *newFirst = first->clone(), *newSecond = second->clone();
     108                Type * newFirst = first->clone(), * newSecond = second->clone();
    93109                env.apply( newFirst );
    94110                env.apply( newSecond );
     
    105121        }
    106122
    107         bool typesCompatibleIgnoreQualifiers( Type *first, Type *second, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
     123        bool typesCompatible(
     124                        const ast::Type * first, const ast::Type * second, const ast::SymbolTable & symtab,
     125                        const ast::TypeEnvironment & env ) {
     126                ast::TypeEnvironment newEnv;
     127                ast::OpenVarSet open, closed;
     128                ast::AssertionSet need, have;
     129
     130                ast::ptr<ast::Type> newFirst{ first }, newSecond{ second };
     131                env.apply( newFirst );
     132                env.apply( newSecond );
     133
     134                findOpenVars( newFirst, open, closed, need, have, FirstClosed );
     135                findOpenVars( newSecond, open, closed, need, have, FirstOpen );
     136
     137                return unifyExact(
     138                        newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab );
     139        }
     140
     141        bool typesCompatibleIgnoreQualifiers( const Type * first, const Type * second, const SymTab::Indexer &indexer, const TypeEnvironment &env ) {
    108142                TypeEnvironment newEnv;
    109143                OpenVarSet openVars;
     
    129163        }
    130164
    131         bool isFtype( Type *type ) {
    132                 if ( dynamic_cast< FunctionType* >( type ) ) {
    133                         return true;
    134                 } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( type ) ) {
    135                         return typeInst->get_isFtype();
    136                 } // if
    137                 return false;
    138         }
    139 
    140         bool tyVarCompatible( const TypeDecl::Data & data, Type *type ) {
    141                 switch ( data.kind ) {
    142                   case TypeDecl::Dtype:
    143                         // to bind to an object type variable, the type must not be a function type.
    144                         // if the type variable is specified to be a complete type then the incoming
    145                         // type must also be complete
    146                         // xxx - should this also check that type is not a tuple type and that it's not a ttype?
    147                         return ! isFtype( type ) && (! data.isComplete || type->isComplete() );
    148                   case TypeDecl::Ftype:
    149                         return isFtype( type );
    150                   case TypeDecl::Ttype:
    151                         // ttype unifies with any tuple type
    152                         return dynamic_cast< TupleType * >( type ) || Tuples::isTtype( type );
    153                 } // switch
    154                 return false;
    155         }
    156 
    157         bool bindVar( TypeInstType *typeInst, Type *other, const TypeDecl::Data & data, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
    158                 // remove references from other, so that type variables can only bind to value types
    159                 other = other->stripReferences();
    160                 OpenVarSet::const_iterator tyvar = openVars.find( typeInst->get_name() );
    161                 assert( tyvar != openVars.end() );
    162                 if ( ! tyVarCompatible( tyvar->second, other ) ) {
    163                         return false;
    164                 } // if
    165                 if ( occurs( other, typeInst->get_name(), env ) ) {
    166                         return false;
    167                 } // if
    168                 if ( const EqvClass *curClass = env.lookup( typeInst->get_name() ) ) {
    169                         if ( curClass->type ) {
    170                                 Type *common = 0;
    171                                 // attempt to unify equivalence class type (which has qualifiers stripped, so they must be restored) with the type to bind to
    172                                 std::unique_ptr< Type > newType( curClass->type->clone() );
    173                                 newType->get_qualifiers() = typeInst->get_qualifiers();
    174                                 if ( unifyInexact( newType.get(), other, env, needAssertions, haveAssertions, openVars, widenMode & WidenMode( curClass->allowWidening, true ), indexer, common ) ) {
    175                                         if ( common ) {
    176                                                 common->get_qualifiers() = Type::Qualifiers();
    177                                                 env.add( EqvClass{ *curClass, common } );
    178                                         } // if
    179                                         return true;
    180                                 } else {
    181                                         return false;
    182                                 } // if
    183                         } else {
    184                                 EqvClass newClass { *curClass, other };
    185                                 newClass.type->get_qualifiers() = Type::Qualifiers();
    186                                 newClass.allowWidening = widenMode.widenFirst && widenMode.widenSecond;
    187                                 env.add( std::move(newClass) );
    188                         } // if
    189                 } else {
    190                         EqvClass newClass;
    191                         newClass.vars.insert( typeInst->get_name() );
    192                         newClass.type = other->clone();
    193                         newClass.type->get_qualifiers() = Type::Qualifiers();
    194                         newClass.allowWidening = widenMode.widenFirst && widenMode.widenSecond;
    195                         newClass.data = data;
    196                         env.add( newClass );
    197                 } // if
    198                 return true;
    199         }
    200 
    201         bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
    202                 bool result = true;
    203                 const EqvClass *class1 = env.lookup( var1->get_name() );
    204                 const EqvClass *class2 = env.lookup( var2->get_name() );
    205                 bool widen1 = false, widen2 = false;
    206                 Type *type1 = nullptr, *type2 = nullptr;
    207 
    208                 if ( class1 ) {
    209                         if ( class1->type ) {
    210                                 if ( occurs( class1->type, var2->get_name(), env ) ) {
    211                                         return false;
    212                                 } // if
    213                                 type1 = class1->type->clone();
    214                         } // if
    215                         widen1 = widenMode.widenFirst && class1->allowWidening;
    216                 } // if
    217                 if ( class2 ) {
    218                         if ( class2->type ) {
    219                                 if ( occurs( class2->type, var1->get_name(), env ) ) {
    220                                         return false;
    221                                 } // if
    222                                 type2 = class2->type->clone();
    223                         } // if
    224                         widen2 = widenMode.widenSecond && class2->allowWidening;
    225                 } // if
    226 
    227                 if ( type1 && type2 ) {
    228 //    std::cerr << "has type1 && type2" << std::endl;
    229                         WidenMode newWidenMode ( widen1, widen2 );
    230                         Type *common = 0;
    231                         if ( unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, newWidenMode, indexer, common ) ) {
    232                                 EqvClass newClass1 = *class1;
    233                                 newClass1.vars.insert( class2->vars.begin(), class2->vars.end() );
    234                                 newClass1.allowWidening = widen1 && widen2;
    235                                 if ( common ) {
    236                                         common->get_qualifiers() = Type::Qualifiers();
    237                                         delete newClass1.type;
    238                                         newClass1.type = common;
    239                                 } // if
    240                                 env.add( std::move(newClass1) );
    241                         } else {
    242                                 result = false;
    243                         } // if
    244                 } else if ( class1 && class2 ) {
    245                         if ( type1 ) {
    246                                 EqvClass newClass1 = *class1;
    247                                 newClass1.vars.insert( class2->vars.begin(), class2->vars.end() );
    248                                 newClass1.allowWidening = widen1;
    249                                 env.add( std::move(newClass1) );
    250                         } else {
    251                                 EqvClass newClass2 = *class2;
    252                                 newClass2.vars.insert( class1->vars.begin(), class1->vars.end() );
    253                                 newClass2.allowWidening = widen2;
    254                                 env.add( std::move(newClass2) );
    255                         } // if
    256                 } else if ( class1 ) {
    257                         EqvClass newClass1 = *class1;
    258                         newClass1.vars.insert( var2->get_name() );
    259                         newClass1.allowWidening = widen1;
    260                         env.add( std::move(newClass1) );
    261                 } else if ( class2 ) {
    262                         EqvClass newClass2 = *class2;
    263                         newClass2.vars.insert( var1->get_name() );
    264                         newClass2.allowWidening = widen2;
    265                         env.add( std::move(newClass2) );
    266                 } else {
    267                         EqvClass newClass;
    268                         newClass.vars.insert( var1->get_name() );
    269                         newClass.vars.insert( var2->get_name() );
    270                         newClass.allowWidening = widen1 && widen2;
    271                         newClass.data = data;
    272                         env.add( newClass );
    273                 } // if
    274                 delete type1;
    275                 delete type2;
    276                 return result;
     165        bool typesCompatibleIgnoreQualifiers(
     166                        const ast::Type * first, const ast::Type * second, const ast::SymbolTable & symtab,
     167                        const ast::TypeEnvironment & env ) {
     168                ast::TypeEnvironment newEnv;
     169                ast::OpenVarSet open;
     170                ast::AssertionSet need, have;
     171
     172                ast::ptr<ast::Type> newFirst{ first }, newSecond{ second };
     173                env.apply( newFirst );
     174                env.apply( newSecond );
     175                reset_qualifiers( newFirst );
     176                reset_qualifiers( newSecond );
     177
     178                return unifyExact(
     179                        newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab );
    277180        }
    278181
     
    299202        }
    300203
    301         bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) {
     204        bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer ) {
    302205#ifdef DEBUG
    303206                TypeEnvironment debugEnv( env );
     
    320223                bool isopen2 = var2 && ( entry2 != openVars.end() );
    321224
    322                 if ( isopen1 && isopen2 && entry1->second == entry2->second ) {
    323                         result = bindVarToVar( var1, var2, entry1->second, env, needAssertions, haveAssertions, openVars, widenMode, indexer );
     225                if ( isopen1 && isopen2 ) {
     226                        if ( entry1->second.kind != entry2->second.kind ) {
     227                                result = false;
     228                        } else {
     229                                result = env.bindVarToVar(
     230                                        var1, var2, TypeDecl::Data{ entry1->second, entry2->second }, needAssertions,
     231                                        haveAssertions, openVars, widen, indexer );
     232                        }
    324233                } else if ( isopen1 ) {
    325                         result = bindVar( var1, type2, entry1->second, env, needAssertions, haveAssertions, openVars, widenMode, indexer );
    326                 } else if ( isopen2 ) { // TODO: swap widenMode values in call, since type positions are flipped?
    327                         result = bindVar( var2, type1, entry2->second, env, needAssertions, haveAssertions, openVars, widenMode, indexer );
     234                        result = env.bindVar( var1, type2, entry1->second, needAssertions, haveAssertions, openVars, widen, indexer );
     235                } else if ( isopen2 ) { // TODO: swap widen values in call, since type positions are flipped?
     236                        result = env.bindVar( var2, type1, entry2->second, needAssertions, haveAssertions, openVars, widen, indexer );
    328237                } else {
    329                         PassVisitor<Unify> comparator( type2, env, needAssertions, haveAssertions, openVars, widenMode, indexer );
     238                        PassVisitor<Unify_old> comparator( type2, env, needAssertions, haveAssertions, openVars, widen, indexer );
    330239                        type1->accept( comparator );
    331240                        result = comparator.pass.get_result();
     
    352261        }
    353262
    354         bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer, Type *&common ) {
     263        bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common ) {
    355264                Type::Qualifiers tq1 = type1->get_qualifiers(), tq2 = type2->get_qualifiers();
    356265                type1->get_qualifiers() = Type::Qualifiers();
     
    364273                std::cerr << std::endl;
    365274#endif
    366                 if ( ! unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, widenMode, indexer ) ) {
     275                if ( ! unifyExact( type1, type2, env, needAssertions, haveAssertions, openVars, widen, indexer ) ) {
    367276#ifdef DEBUG
    368277                        std::cerr << "unifyInexact: no exact unification found" << std::endl;
    369278#endif
    370                         if ( ( common = commonType( type1, type2, widenMode.widenFirst, widenMode.widenSecond, indexer, env, openVars ) ) ) {
    371                                 common->get_qualifiers() = tq1 | tq2;
     279                        if ( ( common = commonType( type1, type2, widen.first, widen.second, indexer, env, openVars ) ) ) {
     280                                common->tq = tq1.unify( tq2 );
    372281#ifdef DEBUG
    373282                                std::cerr << "unifyInexact: common type is ";
     
    384293                } else {
    385294                        if ( tq1 != tq2 ) {
    386                                 if ( ( tq1 > tq2 || widenMode.widenFirst ) && ( tq2 > tq1 || widenMode.widenSecond ) ) {
     295                                if ( ( tq1 > tq2 || widen.first ) && ( tq2 > tq1 || widen.second ) ) {
    387296                                        common = type1->clone();
    388                                         common->get_qualifiers() = tq1 | tq2;
     297                                        common->tq = tq1.unify( tq2 );
    389298                                        result = true;
    390299                                } else {
     
    393302                        } else {
    394303                                common = type1->clone();
    395                                 common->get_qualifiers() = tq1 | tq2;
     304                                common->tq = tq1.unify( tq2 );
    396305                                result = true;
    397306                        } // if
     
    402311        }
    403312
    404         Unify::Unify( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer )
    405                 : result( false ), type2( type2 ), env( env ), needAssertions( needAssertions ), haveAssertions( haveAssertions ), openVars( openVars ), widenMode( widenMode ), indexer( indexer ) {
    406         }
    407 
    408         void Unify::postvisit( __attribute__((unused)) VoidType *voidType) {
     313        Unify_old::Unify_old( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer )
     314                : result( false ), type2( type2 ), env( env ), needAssertions( needAssertions ), haveAssertions( haveAssertions ), openVars( openVars ), widen( widen ), indexer( indexer ) {
     315        }
     316
     317        void Unify_old::postvisit( __attribute__((unused)) VoidType *voidType) {
    409318                result = dynamic_cast< VoidType* >( type2 );
    410319        }
    411320
    412         void Unify::postvisit(BasicType *basicType) {
     321        void Unify_old::postvisit(BasicType *basicType) {
    413322                if ( BasicType *otherBasic = dynamic_cast< BasicType* >( type2 ) ) {
    414323                        result = basicType->get_kind() == otherBasic->get_kind();
     
    438347        }
    439348
    440         void Unify::postvisit(PointerType *pointerType) {
     349        void Unify_old::postvisit(PointerType *pointerType) {
    441350                if ( PointerType *otherPointer = dynamic_cast< PointerType* >( type2 ) ) {
    442351                        result = unifyExact( pointerType->get_base(), otherPointer->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     
    446355        }
    447356
    448         void Unify::postvisit(ReferenceType *refType) {
     357        void Unify_old::postvisit(ReferenceType *refType) {
    449358                if ( ReferenceType *otherRef = dynamic_cast< ReferenceType* >( type2 ) ) {
    450359                        result = unifyExact( refType->get_base(), otherRef->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
     
    454363        }
    455364
    456         void Unify::postvisit(ArrayType *arrayType) {
     365        void Unify_old::postvisit(ArrayType *arrayType) {
    457366                ArrayType *otherArray = dynamic_cast< ArrayType* >( type2 );
    458367                // to unify, array types must both be VLA or both not VLA
     
    534443        /// If this isn't done then argument lists can have wildly different
    535444        /// size and structure, when they should be compatible.
    536         struct TtypeExpander : public WithShortCircuiting {
     445        struct TtypeExpander_old : public WithShortCircuiting {
    537446                TypeEnvironment & tenv;
    538                 TtypeExpander( TypeEnvironment & tenv ) : tenv( tenv ) {}
     447                TtypeExpander_old( TypeEnvironment & tenv ) : tenv( tenv ) {}
    539448                void premutate( TypeInstType * ) { visit_children = false; }
    540449                Type * postmutate( TypeInstType * typeInst ) {
     
    555464                dst.clear();
    556465                for ( DeclarationWithType * dcl : src ) {
    557                         PassVisitor<TtypeExpander> expander( env );
     466                        PassVisitor<TtypeExpander_old> expander( env );
    558467                        dcl->acceptMutator( expander );
    559468                        std::list< Type * > types;
     
    570479        }
    571480
    572         void Unify::postvisit(FunctionType *functionType) {
     481        void Unify_old::postvisit(FunctionType *functionType) {
    573482                FunctionType *otherFunction = dynamic_cast< FunctionType* >( type2 );
    574483                if ( otherFunction && functionType->get_isVarArgs() == otherFunction->get_isVarArgs() ) {
     
    581490
    582491                        // sizes don't have to match if ttypes are involved; need to be more precise wrt where the ttype is to prevent errors
    583                         if ( (flatFunc->parameters.size() == flatOther->parameters.size() && flatFunc->returnVals.size() == flatOther->returnVals.size()) || flatFunc->isTtype() || flatOther->isTtype() ) {
     492                        if (
     493                                        (flatFunc->parameters.size() == flatOther->parameters.size() &&
     494                                                flatFunc->returnVals.size() == flatOther->returnVals.size())
     495                                        || flatFunc->isTtype()
     496                                        || flatOther->isTtype()
     497                        ) {
    584498                                if ( unifyDeclList( flatFunc->parameters.begin(), flatFunc->parameters.end(), flatOther->parameters.begin(), flatOther->parameters.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
    585499                                        if ( unifyDeclList( flatFunc->returnVals.begin(), flatFunc->returnVals.end(), flatOther->returnVals.begin(), flatOther->returnVals.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
     
    597511
    598512        template< typename RefType >
    599         void Unify::handleRefType( RefType *inst, Type *other ) {
     513        void Unify_old::handleRefType( RefType *inst, Type *other ) {
    600514                // check that other type is compatible and named the same
    601515                RefType *otherStruct = dynamic_cast< RefType* >( other );
     
    604518
    605519        template< typename RefType >
    606         void Unify::handleGenericRefType( RefType *inst, Type *other ) {
     520        void Unify_old::handleGenericRefType( RefType *inst, Type *other ) {
    607521                // Check that other type is compatible and named the same
    608522                handleRefType( inst, other );
     
    672586        }
    673587
    674         void Unify::postvisit(StructInstType *structInst) {
     588        void Unify_old::postvisit(StructInstType *structInst) {
    675589                handleGenericRefType( structInst, type2 );
    676590        }
    677591
    678         void Unify::postvisit(UnionInstType *unionInst) {
     592        void Unify_old::postvisit(UnionInstType *unionInst) {
    679593                handleGenericRefType( unionInst, type2 );
    680594        }
    681595
    682         void Unify::postvisit(EnumInstType *enumInst) {
     596        void Unify_old::postvisit(EnumInstType *enumInst) {
    683597                handleRefType( enumInst, type2 );
    684598        }
    685599
    686         void Unify::postvisit(TraitInstType *contextInst) {
     600        void Unify_old::postvisit(TraitInstType *contextInst) {
    687601                handleRefType( contextInst, type2 );
    688602        }
    689603
    690         void Unify::postvisit(TypeInstType *typeInst) {
     604        void Unify_old::postvisit(TypeInstType *typeInst) {
    691605                assert( openVars.find( typeInst->get_name() ) == openVars.end() );
    692606                TypeInstType *otherInst = dynamic_cast< TypeInstType* >( type2 );
     
    743657        }
    744658
    745         void Unify::postvisit(TupleType *tupleType) {
     659        void Unify_old::postvisit(TupleType *tupleType) {
    746660                if ( TupleType *otherTuple = dynamic_cast< TupleType* >( type2 ) ) {
    747661                        std::unique_ptr<TupleType> flat1( tupleType->clone() );
     
    749663                        std::list<Type *> types1, types2;
    750664
    751                         PassVisitor<TtypeExpander> expander( env );
     665                        PassVisitor<TtypeExpander_old> expander( env );
    752666                        flat1->acceptMutator( expander );
    753667                        flat2->acceptMutator( expander );
     
    760674        }
    761675
    762         void Unify::postvisit( __attribute__((unused)) VarArgsType *varArgsType ) {
     676        void Unify_old::postvisit( __attribute__((unused)) VarArgsType *varArgsType ) {
    763677                result = dynamic_cast< VarArgsType* >( type2 );
    764678        }
    765679
    766         void Unify::postvisit( __attribute__((unused)) ZeroType *zeroType ) {
     680        void Unify_old::postvisit( __attribute__((unused)) ZeroType *zeroType ) {
    767681                result = dynamic_cast< ZeroType* >( type2 );
    768682        }
    769683
    770         void Unify::postvisit( __attribute__((unused)) OneType *oneType ) {
     684        void Unify_old::postvisit( __attribute__((unused)) OneType *oneType ) {
    771685                result = dynamic_cast< OneType* >( type2 );
    772686        }
    773687
    774         // xxx - compute once and store in the FunctionType?
    775688        Type * extractResultType( FunctionType * function ) {
    776689                if ( function->get_returnVals().size() == 0 ) {
     
    786699                }
    787700        }
     701
     702        class Unify_new final : public ast::WithShortCircuiting {
     703                const ast::Type * type2;
     704                ast::TypeEnvironment & tenv;
     705                ast::AssertionSet & need;
     706                ast::AssertionSet & have;
     707                const ast::OpenVarSet & open;
     708                WidenMode widen;
     709                const ast::SymbolTable & symtab;
     710        public:
     711                bool result;
     712
     713                Unify_new(
     714                        const ast::Type * type2, ast::TypeEnvironment & env, ast::AssertionSet & need,
     715                        ast::AssertionSet & have, const ast::OpenVarSet & open, WidenMode widen,
     716                        const ast::SymbolTable & symtab )
     717                : type2(type2), tenv(env), need(need), have(have), open(open), widen(widen),
     718                  symtab(symtab), result(false) {}
     719
     720                void previsit( const ast::Node * ) { visit_children = false; }
     721
     722                void postvisit( const ast::VoidType * ) {
     723                        result = dynamic_cast< const ast::VoidType * >( type2 );
     724                }
     725
     726                void postvisit( const ast::BasicType * basic ) {
     727                        if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) {
     728                                result = basic->kind == basic2->kind;
     729                        }
     730                }
     731
     732                void postvisit( const ast::PointerType * pointer ) {
     733                        if ( auto pointer2 = dynamic_cast< const ast::PointerType * >( type2 ) ) {
     734                                result = unifyExact(
     735                                        pointer->base, pointer2->base, tenv, need, have, open,
     736                                        noWiden(), symtab );
     737                        }
     738                }
     739
     740                void postvisit( const ast::ArrayType * array ) {
     741                        auto array2 = dynamic_cast< const ast::ArrayType * >( type2 );
     742                        if ( ! array2 ) return;
     743
     744                        // to unify, array types must both be VLA or both not VLA and both must have a
     745                        // dimension expression or not have a dimension
     746                        if ( array->isVarLen != array2->isVarLen ) return;
     747                        if ( ! array->isVarLen && ! array2->isVarLen
     748                                        && array->dimension && array2->dimension ) {
     749                                auto ce1 = array->dimension.as< ast::ConstantExpr >();
     750                                auto ce2 = array2->dimension.as< ast::ConstantExpr >();
     751
     752                                // see C11 Reference Manual 6.7.6.2.6
     753                                // two array types with size specifiers that are integer constant expressions are
     754                                // compatible if both size specifiers have the same constant value
     755                                if ( ce1 && ce2 && ce1->intValue() != ce2->intValue() ) return;
     756                        }
     757
     758                        result = unifyExact(
     759                                array->base, array2->base, tenv, need, have, open, noWiden(),
     760                                symtab );
     761                }
     762
     763                void postvisit( const ast::ReferenceType * ref ) {
     764                        if ( auto ref2 = dynamic_cast< const ast::ReferenceType * >( type2 ) ) {
     765                                result = unifyExact(
     766                                        ref->base, ref2->base, tenv, need, have, open, noWiden(),
     767                                        symtab );
     768                        }
     769                }
     770
     771        private:
     772                /// Replaces ttype variables with their bound types.
     773                /// If this isn't done when satifying ttype assertions, then argument lists can have
     774                /// different size and structure when they should be compatible.
     775                struct TtypeExpander_new : public ast::WithShortCircuiting {
     776                        ast::TypeEnvironment & tenv;
     777
     778                        TtypeExpander_new( ast::TypeEnvironment & env ) : tenv( env ) {}
     779
     780                        const ast::Type * postvisit( const ast::TypeInstType * typeInst ) {
     781                                if ( const ast::EqvClass * clz = tenv.lookup( typeInst->name ) ) {
     782                                        // expand ttype parameter into its actual type
     783                                        if ( clz->data.kind == ast::TypeVar::Ttype && clz->bound ) {
     784                                                return clz->bound;
     785                                        }
     786                                }
     787                                return typeInst;
     788                        }
     789                };
     790
     791                /// returns flattened version of `src`
     792                static std::vector< ast::ptr< ast::DeclWithType > > flattenList(
     793                        const std::vector< ast::ptr< ast::DeclWithType > > & src, ast::TypeEnvironment & env
     794                ) {
     795                        std::vector< ast::ptr< ast::DeclWithType > > dst;
     796                        dst.reserve( src.size() );
     797                        for ( const ast::DeclWithType * d : src ) {
     798                                ast::Pass<TtypeExpander_new> expander{ env };
     799                                d = d->accept( expander );
     800                                auto types = flatten( d->get_type() );
     801                                for ( ast::ptr< ast::Type > & t : types ) {
     802                                        // outermost const, volatile, _Atomic qualifiers in parameters should not play
     803                                        // a role in the unification of function types, since they do not determine
     804                                        // whether a function is callable.
     805                                        // NOTE: **must** consider at least mutex qualifier, since functions can be
     806                                        // overloaded on outermost mutex and a mutex function has different
     807                                        // requirements than a non-mutex function
     808                                        remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic );
     809                                        dst.emplace_back( new ast::ObjectDecl{ d->location, "", t } );
     810                                }
     811                        }
     812                        return dst;
     813                }
     814
     815                /// Creates a tuple type based on a list of DeclWithType
     816                template< typename Iter >
     817                static ast::ptr< ast::Type > tupleFromDecls( Iter crnt, Iter end ) {
     818                        std::vector< ast::ptr< ast::Type > > types;
     819                        while ( crnt != end ) {
     820                                // it is guaranteed that a ttype variable will be bound to a flat tuple, so ensure
     821                                // that this results in a flat tuple
     822                                flatten( (*crnt)->get_type(), types );
     823
     824                                ++crnt;
     825                        }
     826
     827                        return { new ast::TupleType{ std::move(types) } };
     828                }
     829
     830                template< typename Iter >
     831                static bool unifyDeclList(
     832                        Iter crnt1, Iter end1, Iter crnt2, Iter end2, ast::TypeEnvironment & env,
     833                        ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
     834                        const ast::SymbolTable & symtab
     835                ) {
     836                        while ( crnt1 != end1 && crnt2 != end2 ) {
     837                                const ast::Type * t1 = (*crnt1)->get_type();
     838                                const ast::Type * t2 = (*crnt2)->get_type();
     839                                bool isTuple1 = Tuples::isTtype( t1 );
     840                                bool isTuple2 = Tuples::isTtype( t2 );
     841
     842                                // assumes here that ttype *must* be last parameter
     843                                if ( isTuple1 && ! isTuple2 ) {
     844                                        // combine remainder of list2, then unify
     845                                        return unifyExact(
     846                                                t1, tupleFromDecls( crnt2, end2 ), env, need, have, open,
     847                                                noWiden(), symtab );
     848                                } else if ( ! isTuple1 && isTuple2 ) {
     849                                        // combine remainder of list1, then unify
     850                                        return unifyExact(
     851                                                tupleFromDecls( crnt1, end1 ), t2, env, need, have, open,
     852                                                noWiden(), symtab );
     853                                }
     854
     855                                if ( ! unifyExact(
     856                                        t1, t2, env, need, have, open, noWiden(), symtab )
     857                                ) return false;
     858
     859                                ++crnt1; ++crnt2;
     860                        }
     861
     862                        // May get to the end of one argument list before the other. This is only okay if the
     863                        // other is a ttype
     864                        if ( crnt1 != end1 ) {
     865                                // try unifying empty tuple with ttype
     866                                const ast::Type * t1 = (*crnt1)->get_type();
     867                                if ( ! Tuples::isTtype( t1 ) ) return false;
     868                                return unifyExact(
     869                                        t1, tupleFromDecls( crnt2, end2 ), env, need, have, open,
     870                                        noWiden(), symtab );
     871                        } else if ( crnt2 != end2 ) {
     872                                // try unifying empty tuple with ttype
     873                                const ast::Type * t2 = (*crnt2)->get_type();
     874                                if ( ! Tuples::isTtype( t2 ) ) return false;
     875                                return unifyExact(
     876                                        tupleFromDecls( crnt1, end1 ), t2, env, need, have, open,
     877                                        noWiden(), symtab );
     878                        }
     879
     880                        return true;
     881                }
     882
     883                static bool unifyDeclList(
     884                        const std::vector< ast::ptr< ast::DeclWithType > > & list1,
     885                        const std::vector< ast::ptr< ast::DeclWithType > > & list2,
     886                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
     887                        const ast::OpenVarSet & open, const ast::SymbolTable & symtab
     888                ) {
     889                        return unifyDeclList(
     890                                list1.begin(), list1.end(), list2.begin(), list2.end(), env, need, have, open,
     891                                symtab );
     892                }
     893
     894                static void markAssertionSet( ast::AssertionSet & assns, const ast::DeclWithType * assn ) {
     895                        auto i = assns.find( assn );
     896                        if ( i != assns.end() ) {
     897                                i->second.isUsed = true;
     898                        }
     899                }
     900
     901                /// mark all assertions in `type` used in both `assn1` and `assn2`
     902                static void markAssertions(
     903                        ast::AssertionSet & assn1, ast::AssertionSet & assn2,
     904                        const ast::ParameterizedType * type
     905                ) {
     906                        for ( const auto & tyvar : type->forall ) {
     907                                for ( const ast::DeclWithType * assert : tyvar->assertions ) {
     908                                        markAssertionSet( assn1, assert );
     909                                        markAssertionSet( assn2, assert );
     910                                }
     911                        }
     912                }
     913
     914        public:
     915                void postvisit( const ast::FunctionType * func ) {
     916                        auto func2 = dynamic_cast< const ast::FunctionType * >( type2 );
     917                        if ( ! func2 ) return;
     918
     919                        if ( func->isVarArgs != func2->isVarArgs ) return;
     920
     921                        // Flatten the parameter lists for both functions so that tuple structure does not
     922                        // affect unification. Does not actually mutate function parameters.
     923                        auto params = flattenList( func->params, tenv );
     924                        auto params2 = flattenList( func2->params, tenv );
     925
     926                        // sizes don't have to match if ttypes are involved; need to be more precise w.r.t.
     927                        // where the ttype is to prevent errors
     928                        if (
     929                                ( params.size() != params2.size() || func->returns.size() != func2->returns.size() )
     930                                && ! func->isTtype()
     931                                && ! func2->isTtype()
     932                        ) return;
     933
     934                        if ( ! unifyDeclList( params, params2, tenv, need, have, open, symtab ) ) return;
     935                        if ( ! unifyDeclList(
     936                                func->returns, func2->returns, tenv, need, have, open, symtab ) ) return;
     937
     938                        markAssertions( have, need, func );
     939                        markAssertions( have, need, func2 );
     940
     941                        result = true;
     942                }
     943
     944        private:
     945                template< typename RefType >
     946                const RefType * handleRefType( const RefType * inst, const ast::Type * other ) {
     947                        // check that the other type is compatible and named the same
     948                        auto otherInst = dynamic_cast< const RefType * >( other );
     949                        result = otherInst && inst->name == otherInst->name;
     950                        return otherInst;
     951                }
     952
     953                /// Creates a tuple type based on a list of TypeExpr
     954                template< typename Iter >
     955                static const ast::Type * tupleFromExprs(
     956                        const ast::TypeExpr * param, Iter & crnt, Iter end, ast::CV::Qualifiers qs
     957                ) {
     958                        std::vector< ast::ptr< ast::Type > > types;
     959                        do {
     960                                types.emplace_back( param->type );
     961
     962                                ++crnt;
     963                                if ( crnt == end ) break;
     964                                param = strict_dynamic_cast< const ast::TypeExpr * >( crnt->get() );
     965                        } while(true);
     966
     967                        return new ast::TupleType{ std::move(types), qs };
     968                }
     969
     970                template< typename RefType >
     971                void handleGenericRefType( const RefType * inst, const ast::Type * other ) {
     972                        // check that other type is compatible and named the same
     973                        const RefType * inst2 = handleRefType( inst, other );
     974                        if ( ! inst2 ) return;
     975
     976                        // check that parameters of types unify, if any
     977                        const std::vector< ast::ptr< ast::Expr > > & params = inst->params;
     978                        const std::vector< ast::ptr< ast::Expr > > & params2 = inst2->params;
     979
     980                        auto it = params.begin();
     981                        auto jt = params2.begin();
     982                        for ( ; it != params.end() && jt != params2.end(); ++it, ++jt ) {
     983                                auto param = strict_dynamic_cast< const ast::TypeExpr * >( it->get() );
     984                                auto param2 = strict_dynamic_cast< const ast::TypeExpr * >( jt->get() );
     985
     986                                ast::ptr< ast::Type > pty = param->type;
     987                                ast::ptr< ast::Type > pty2 = param2->type;
     988
     989                                bool isTuple = Tuples::isTtype( pty );
     990                                bool isTuple2 = Tuples::isTtype( pty2 );
     991
     992                                if ( isTuple && isTuple2 ) {
     993                                        ++it; ++jt;  // skip ttype parameters before break
     994                                } else if ( isTuple ) {
     995                                        // bundle remaining params into tuple
     996                                        pty2 = tupleFromExprs( param2, jt, params2.end(), pty->qualifiers );
     997                                        ++it;  // skip ttype parameter for break
     998                                } else if ( isTuple2 ) {
     999                                        // bundle remaining params into tuple
     1000                                        pty = tupleFromExprs( param, it, params.end(), pty2->qualifiers );
     1001                                        ++jt;  // skip ttype parameter for break
     1002                                }
     1003
     1004                                if ( ! unifyExact(
     1005                                                pty, pty2, tenv, need, have, open, noWiden(), symtab ) ) {
     1006                                        result = false;
     1007                                        return;
     1008                                }
     1009
     1010                                // ttype parameter should be last
     1011                                if ( isTuple || isTuple2 ) break;
     1012                        }
     1013                        result = it == params.end() && jt == params2.end();
     1014                }
     1015
     1016        public:
     1017                void postvisit( const ast::StructInstType * aggrType ) {
     1018                        handleGenericRefType( aggrType, type2 );
     1019                }
     1020
     1021                void postvisit( const ast::UnionInstType * aggrType ) {
     1022                        handleGenericRefType( aggrType, type2 );
     1023                }
     1024
     1025                void postvisit( const ast::EnumInstType * aggrType ) {
     1026                        handleRefType( aggrType, type2 );
     1027                }
     1028
     1029                void postvisit( const ast::TraitInstType * aggrType ) {
     1030                        handleRefType( aggrType, type2 );
     1031                }
     1032
     1033                void postvisit( const ast::TypeInstType * typeInst ) {
     1034                        assert( open.find( typeInst->name ) == open.end() );
     1035                        handleRefType( typeInst, type2 );
     1036                }
     1037
     1038        private:
     1039                /// Creates a tuple type based on a list of Type
     1040                static ast::ptr< ast::Type > tupleFromTypes(
     1041                        const std::vector< ast::ptr< ast::Type > > & tys
     1042                ) {
     1043                        std::vector< ast::ptr< ast::Type > > out;
     1044                        for ( const ast::Type * ty : tys ) {
     1045                                // it is guaranteed that a ttype variable will be bound to a flat tuple, so ensure
     1046                                // that this results in a flat tuple
     1047                                flatten( ty, out );
     1048                        }
     1049
     1050                        return { new ast::TupleType{ std::move(out) } };
     1051                }
     1052
     1053                static bool unifyList(
     1054                        const std::vector< ast::ptr< ast::Type > > & list1,
     1055                        const std::vector< ast::ptr< ast::Type > > & list2, ast::TypeEnvironment & env,
     1056                        ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
     1057                        const ast::SymbolTable & symtab
     1058                ) {
     1059                        auto crnt1 = list1.begin();
     1060                        auto crnt2 = list2.begin();
     1061                        while ( crnt1 != list1.end() && crnt2 != list2.end() ) {
     1062                                const ast::Type * t1 = *crnt1;
     1063                                const ast::Type * t2 = *crnt2;
     1064                                bool isTuple1 = Tuples::isTtype( t1 );
     1065                                bool isTuple2 = Tuples::isTtype( t2 );
     1066
     1067                                // assumes ttype must be last parameter
     1068                                if ( isTuple1 && ! isTuple2 ) {
     1069                                        // combine entirety of list2, then unify
     1070                                        return unifyExact(
     1071                                                t1, tupleFromTypes( list2 ), env, need, have, open,
     1072                                                noWiden(), symtab );
     1073                                } else if ( ! isTuple1 && isTuple2 ) {
     1074                                        // combine entirety of list1, then unify
     1075                                        return unifyExact(
     1076                                                tupleFromTypes( list1 ), t2, env, need, have, open,
     1077                                                noWiden(), symtab );
     1078                                }
     1079
     1080                                if ( ! unifyExact(
     1081                                        t1, t2, env, need, have, open, noWiden(), symtab )
     1082                                ) return false;
     1083
     1084                                ++crnt1; ++crnt2;
     1085                        }
     1086
     1087                        if ( crnt1 != list1.end() ) {
     1088                                // try unifying empty tuple type with ttype
     1089                                const ast::Type * t1 = *crnt1;
     1090                                if ( ! Tuples::isTtype( t1 ) ) return false;
     1091                                // xxx - this doesn't generate an empty tuple, contrary to comment; both ported
     1092                                // from Rob's code
     1093                                return unifyExact(
     1094                                                t1, tupleFromTypes( list2 ), env, need, have, open,
     1095                                                noWiden(), symtab );
     1096                        } else if ( crnt2 != list2.end() ) {
     1097                                // try unifying empty tuple with ttype
     1098                                const ast::Type * t2 = *crnt2;
     1099                                if ( ! Tuples::isTtype( t2 ) ) return false;
     1100                                // xxx - this doesn't generate an empty tuple, contrary to comment; both ported
     1101                                // from Rob's code
     1102                                return unifyExact(
     1103                                                tupleFromTypes( list1 ), t2, env, need, have, open,
     1104                                                noWiden(), symtab );
     1105                        }
     1106
     1107                        return true;
     1108                }
     1109
     1110        public:
     1111                void postvisit( const ast::TupleType * tuple ) {
     1112                        auto tuple2 = dynamic_cast< const ast::TupleType * >( type2 );
     1113                        if ( ! tuple2 ) return;
     1114
     1115                        ast::Pass<TtypeExpander_new> expander{ tenv };
     1116                        const ast::Type * flat = tuple->accept( expander );
     1117                        const ast::Type * flat2 = tuple2->accept( expander );
     1118
     1119                        auto types = flatten( flat );
     1120                        auto types2 = flatten( flat2 );
     1121
     1122                        result = unifyList( types, types2, tenv, need, have, open, symtab );
     1123                }
     1124
     1125                void postvisit( const ast::VarArgsType * ) {
     1126                        result = dynamic_cast< const ast::VarArgsType * >( type2 );
     1127                }
     1128
     1129                void postvisit( const ast::ZeroType * ) {
     1130                        result = dynamic_cast< const ast::ZeroType * >( type2 );
     1131                }
     1132
     1133                void postvisit( const ast::OneType * ) {
     1134                        result = dynamic_cast< const ast::OneType * >( type2 );
     1135                }
     1136
     1137          private:
     1138                template< typename RefType > void handleRefType( RefType *inst, Type *other );
     1139                template< typename RefType > void handleGenericRefType( RefType *inst, Type *other );
     1140        };
     1141
     1142        bool unify(
     1143                        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
     1144                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
     1145                        ast::OpenVarSet & open, const ast::SymbolTable & symtab
     1146        ) {
     1147                ast::ptr<ast::Type> common;
     1148                return unify( type1, type2, env, need, have, open, symtab, common );
     1149        }
     1150
     1151        bool unify(
     1152                        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
     1153                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
     1154                        ast::OpenVarSet & open, const ast::SymbolTable & symtab, ast::ptr<ast::Type> & common
     1155        ) {
     1156                ast::OpenVarSet closed;
     1157                findOpenVars( type1, open, closed, need, have, FirstClosed );
     1158                findOpenVars( type2, open, closed, need, have, FirstOpen );
     1159                return unifyInexact(
     1160                        type1, type2, env, need, have, open, WidenMode{ true, true }, symtab, common );
     1161        }
     1162
     1163        bool unifyExact(
     1164                        const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
     1165                        ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
     1166                        WidenMode widen, const ast::SymbolTable & symtab
     1167        ) {
     1168                if ( type1->qualifiers != type2->qualifiers ) return false;
     1169
     1170                auto var1 = dynamic_cast< const ast::TypeInstType * >( type1 );
     1171                auto var2 = dynamic_cast< const ast::TypeInstType * >( type2 );
     1172                ast::OpenVarSet::const_iterator
     1173                        entry1 = var1 ? open.find( var1->name ) : open.end(),
     1174                        entry2 = var2 ? open.find( var2->name ) : open.end();
     1175                bool isopen1 = entry1 != open.end();
     1176                bool isopen2 = entry2 != open.end();
     1177
     1178                if ( isopen1 && isopen2 ) {
     1179                        if ( entry1->second.kind != entry2->second.kind ) return false;
     1180                        return env.bindVarToVar(
     1181                                var1, var2, ast::TypeDecl::Data{ entry1->second, entry2->second }, need, have,
     1182                                open, widen, symtab );
     1183                } else if ( isopen1 ) {
     1184                        return env.bindVar( var1, type2, entry1->second, need, have, open, widen, symtab );
     1185                } else if ( isopen2 ) {
     1186                        return env.bindVar( var2, type1, entry2->second, need, have, open, widen, symtab );
     1187                } else {
     1188                        ast::Pass<Unify_new> comparator{ type2, env, need, have, open, widen, symtab };
     1189                        type1->accept( comparator );
     1190                        return comparator.pass.result;
     1191                }
     1192        }
     1193
     1194        bool unifyInexact(
     1195                        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
     1196                        ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
     1197                        const ast::OpenVarSet & open, WidenMode widen, const ast::SymbolTable & symtab,
     1198                        ast::ptr<ast::Type> & common
     1199        ) {
     1200                ast::CV::Qualifiers q1 = type1->qualifiers, q2 = type2->qualifiers;
     1201
     1202                // force t1 and t2 to be cloned if their qualifiers must be stripped, so that type1 and
     1203                // type2 are left unchanged; calling convention forces type{1,2}->strong_ref >= 1
     1204                ast::ptr<ast::Type> t1{ type1 }, t2{ type2 };
     1205                reset_qualifiers( t1 );
     1206                reset_qualifiers( t2 );
     1207
     1208                if ( unifyExact( t1, t2, env, need, have, open, widen, symtab ) ) {
     1209                        t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones
     1210
     1211                        // if exact unification on unqualified types, try to merge qualifiers
     1212                        if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) {
     1213                                common = type1;
     1214                                reset_qualifiers( common, q1 | q2 );
     1215                                return true;
     1216                        } else {
     1217                                return false;
     1218                        }
     1219
     1220                } else if (( common = commonType( t1, t2, widen, symtab, env, open ) )) {
     1221                        t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones
     1222
     1223                        // no exact unification, but common type
     1224                        reset_qualifiers( common, q1 | q2 );
     1225                        return true;
     1226                } else {
     1227                        return false;
     1228                }
     1229        }
     1230
     1231        ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func ) {
     1232                if ( func->returns.empty() ) return new ast::VoidType{};
     1233                if ( func->returns.size() == 1 ) return func->returns[0]->get_type();
     1234
     1235                std::vector<ast::ptr<ast::Type>> tys;
     1236                for ( const ast::DeclWithType * decl : func->returns ) {
     1237                        tys.emplace_back( decl->get_type() );
     1238                }
     1239                return new ast::TupleType{ std::move(tys) };
     1240        }
    7881241} // namespace ResolvExpr
    7891242
  • src/ResolvExpr/Unify.h

    r7951100 rb067d9b  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 13:09:04 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jul 21 23:09:34 2017
    13 // Update Count     : 3
     11// Last Modified By : Aaron B. Moss
     12// Last Modified On : Mon Jun 18 11:58:00 2018
     13// Update Count     : 4
    1414//
    1515
     
    1818#include <list>                   // for list
    1919
     20#include "AST/Node.hpp"             // for ptr
     21#include "AST/TypeEnvironment.hpp"  // for TypeEnvironment, AssertionSet, OpenVarSet
    2022#include "Common/utility.h"       // for deleteAll
    2123#include "SynTree/Declaration.h"  // for TypeDecl, TypeDecl::Data
    2224#include "TypeEnvironment.h"      // for AssertionSet, OpenVarSet
     25#include "WidenMode.h"              // for WidenMode
    2326
    2427class Type;
    2528class TypeInstType;
    2629namespace SymTab {
    27 class Indexer;
    28 }  // namespace SymTab
     30        class Indexer;
     31}
     32
     33namespace ast {
     34        class SymbolTable;
     35        class Type;
     36}
    2937
    3038namespace ResolvExpr {
    31         struct WidenMode {
    32                 WidenMode( bool widenFirst, bool widenSecond ): widenFirst( widenFirst ), widenSecond( widenSecond ) {}
    33                 WidenMode &operator|=( const WidenMode &other ) { widenFirst |= other.widenFirst; widenSecond |= other.widenSecond; return *this; }
    34                 WidenMode &operator&=( const WidenMode &other ) { widenFirst &= other.widenFirst; widenSecond &= other.widenSecond; return *this; }
    35                 WidenMode operator|( const WidenMode &other ) { WidenMode newWM( *this ); newWM |= other; return newWM; }
    36                 WidenMode operator&( const WidenMode &other ) { WidenMode newWM( *this ); newWM &= other; return newWM; }
    37                 operator bool() { return widenFirst && widenSecond; }
    38 
    39                 bool widenFirst : 1, widenSecond : 1;
    40         };
    41 
    42         bool bindVar( TypeInstType *typeInst, Type *other, const TypeDecl::Data & data, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );
    4339        bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );
    4440        bool unify( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer, Type *&commonType );
    4541        bool unifyExact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, OpenVarSet &openVars, const SymTab::Indexer &indexer );
     42        bool unifyInexact( Type *type1, Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widen, const SymTab::Indexer &indexer, Type *&common );
    4643
    4744        template< typename Iterator1, typename Iterator2 >
     
    7269        }
    7370
     71        bool unify(
     72                const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
     73                ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
     74                ast::OpenVarSet & open, const ast::SymbolTable & symtab );
     75
     76        bool unify(
     77                const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
     78                ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
     79                ast::OpenVarSet & open, const ast::SymbolTable & symtab, ast::ptr<ast::Type> & common );
     80
     81        bool unifyExact(
     82                const ast::Type * type1, const ast::Type * type2, ast::TypeEnvironment & env,
     83                ast::AssertionSet & need, ast::AssertionSet & have, const ast::OpenVarSet & open,
     84                WidenMode widen, const ast::SymbolTable & symtab );
     85
     86        bool unifyInexact(
     87                const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
     88                ast::TypeEnvironment & env, ast::AssertionSet & need, ast::AssertionSet & have,
     89                const ast::OpenVarSet & open, WidenMode widen, const ast::SymbolTable & symtab,
     90                ast::ptr<ast::Type> & common );
     91
    7492} // namespace ResolvExpr
    7593
  • src/ResolvExpr/module.mk

    r7951100 rb067d9b  
    1515###############################################################################
    1616
    17 SRC += ResolvExpr/AlternativeFinder.cc \
    18        ResolvExpr/Alternative.cc \
    19        ResolvExpr/Unify.cc \
    20        ResolvExpr/PtrsAssignable.cc \
    21        ResolvExpr/CommonType.cc \
    22        ResolvExpr/ConversionCost.cc \
    23        ResolvExpr/CastCost.cc \
    24        ResolvExpr/PtrsCastable.cc \
    25        ResolvExpr/AdjustExprType.cc \
    26        ResolvExpr/AlternativePrinter.cc \
    27        ResolvExpr/Resolver.cc \
    28        ResolvExpr/ResolveTypeof.cc \
    29        ResolvExpr/RenameVars.cc \
    30        ResolvExpr/FindOpenVars.cc \
    31        ResolvExpr/PolyCost.cc \
    32        ResolvExpr/Occurs.cc \
    33        ResolvExpr/TypeEnvironment.cc \
    34        ResolvExpr/CurrentObject.cc \
    35        ResolvExpr/ExplodedActual.cc
     17SRC_RESOLVEXPR = \
     18      ResolvExpr/AdjustExprType.cc \
     19      ResolvExpr/Alternative.cc \
     20      ResolvExpr/AlternativeFinder.cc \
     21      ResolvExpr/Candidate.cpp \
     22      ResolvExpr/CandidateFinder.cpp \
     23      ResolvExpr/CastCost.cc \
     24      ResolvExpr/CommonType.cc \
     25      ResolvExpr/ConversionCost.cc \
     26      ResolvExpr/CurrentObject.cc \
     27      ResolvExpr/ExplodedActual.cc \
     28      ResolvExpr/ExplodedArg.cpp \
     29      ResolvExpr/FindOpenVars.cc \
     30      ResolvExpr/Occurs.cc \
     31      ResolvExpr/PolyCost.cc \
     32      ResolvExpr/PtrsAssignable.cc \
     33      ResolvExpr/PtrsCastable.cc \
     34      ResolvExpr/RenameVars.cc \
     35      ResolvExpr/ResolveAssertions.cc \
     36      ResolvExpr/Resolver.cc \
     37      ResolvExpr/ResolveTypeof.cc \
     38      ResolvExpr/SatisfyAssertions.cpp \
     39      ResolvExpr/SpecCost.cc \
     40      ResolvExpr/TypeEnvironment.cc \
     41      ResolvExpr/Unify.cc
     42
     43SRC += $(SRC_RESOLVEXPR) ResolvExpr/AlternativePrinter.cc
     44SRCDEMANGLE += $(SRC_RESOLVEXPR)
  • src/ResolvExpr/typeops.h

    r7951100 rb067d9b  
    99// Author           : Richard C. Bilson
    1010// Created On       : Sun May 17 07:28:22 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:36:18 2017
    13 // Update Count     : 3
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu Aug  8 16:36:00 2019
     13// Update Count     : 5
    1414//
    1515
     
    1818#include <vector>
    1919
     20#include "Cost.h"
     21#include "TypeEnvironment.h"
     22#include "WidenMode.h"
     23#include "AST/Fwd.hpp"
     24#include "AST/Node.hpp"
     25#include "AST/SymbolTable.hpp"
     26#include "AST/Type.hpp"
     27#include "AST/TypeEnvironment.hpp"
    2028#include "SynTree/SynTree.h"
    2129#include "SynTree/Type.h"
    22 #include "SymTab/Indexer.h"
    23 #include "Cost.h"
    24 #include "TypeEnvironment.h"
     30
     31namespace SymTab {
     32        class Indexer;
     33}
    2534
    2635namespace ResolvExpr {
     
    5463        // in AdjustExprType.cc
    5564        /// Replaces array types with the equivalent pointer, and function types with a pointer-to-function
    56         void adjustExprType( Type *&type, const TypeEnvironment &env, const SymTab::Indexer &indexer );
     65        void adjustExprType( Type *& type, const TypeEnvironment & env, const SymTab::Indexer & indexer );
    5766
    5867        /// Replaces array types with the equivalent pointer, and function types with a pointer-to-function using empty TypeEnvironment and Indexer
     
    6069
    6170        template< typename ForwardIterator >
    62         void adjustExprTypeList( ForwardIterator begin, ForwardIterator end, const TypeEnvironment &env, const SymTab::Indexer &indexer ) {
     71        void adjustExprTypeList( ForwardIterator begin, ForwardIterator end, const TypeEnvironment & env, const SymTab::Indexer & indexer ) {
    6372                while ( begin != end ) {
    6473                        adjustExprType( *begin++, env, indexer );
     
    6675        }
    6776
     77        /// Replaces array types with equivalent pointer, and function types with a pointer-to-function
     78        const ast::Type * adjustExprType(
     79                const ast::Type * type, const ast::TypeEnvironment & env, const ast::SymbolTable & symtab );
     80
    6881        // in CastCost.cc
    69         Cost castCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env );
     82        Cost castCost( const Type * src, const Type * dest, bool srcIsLvalue,
     83                const SymTab::Indexer & indexer, const TypeEnvironment & env );
     84        Cost castCost(
     85                const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
     86                const ast::TypeEnvironment & env );
    7087
    7188        // in ConversionCost.cc
    72         Cost conversionCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env );
     89        Cost conversionCost( const Type * src, const Type * dest, bool srcIsLvalue,
     90                const SymTab::Indexer & indexer, const TypeEnvironment & env );
     91        Cost conversionCost(
     92                const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
     93                const ast::TypeEnvironment & env );
     94
     95        // in AlternativeFinder.cc
     96        Cost computeConversionCost( Type * actualType, Type * formalType, bool actualIsLvalue,
     97                const SymTab::Indexer & indexer, const TypeEnvironment & env );
    7398
    7499        // in PtrsAssignable.cc
    75         int ptrsAssignable( Type *src, Type *dest, const TypeEnvironment &env );
     100        int ptrsAssignable( const Type * src, const Type * dest, const TypeEnvironment & env );
     101        int ptrsAssignable( const ast::Type * src, const ast::Type * dst,
     102                const ast::TypeEnvironment & env );
    76103
    77104        // in PtrsCastable.cc
    78         int ptrsCastable( Type *src, Type *dest, const TypeEnvironment &env, const SymTab::Indexer &indexer );
     105        int ptrsCastable( const Type * src, const Type * dest, const TypeEnvironment & env, const SymTab::Indexer & indexer );
     106        int ptrsCastable(
     107                const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
     108                const ast::TypeEnvironment & env );
    79109
    80110        // in Unify.cc
    81         bool isFtype( Type *type );
    82         bool typesCompatible( Type *, Type *, const SymTab::Indexer &indexer, const TypeEnvironment &env );
    83         bool typesCompatibleIgnoreQualifiers( Type *, Type *, const SymTab::Indexer &indexer, const TypeEnvironment &env );
    84 
    85         inline bool typesCompatible( Type *t1, Type *t2, const SymTab::Indexer &indexer ) {
     111        bool typesCompatible( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env );
     112        bool typesCompatibleIgnoreQualifiers( const Type *, const Type *, const SymTab::Indexer & indexer, const TypeEnvironment & env );
     113
     114        inline bool typesCompatible( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) {
    86115                TypeEnvironment env;
    87116                return typesCompatible( t1, t2, indexer, env );
    88117        }
    89118
    90         inline bool typesCompatibleIgnoreQualifiers( Type *t1, Type *t2, const SymTab::Indexer &indexer ) {
     119        inline bool typesCompatibleIgnoreQualifiers( const Type * t1, const Type * t2, const SymTab::Indexer & indexer ) {
    91120                TypeEnvironment env;
    92121                return typesCompatibleIgnoreQualifiers( t1, t2, indexer, env );
    93122        }
    94123
     124        bool typesCompatible(
     125                const ast::Type *, const ast::Type *, const ast::SymbolTable & symtab = {},
     126                const ast::TypeEnvironment & env = {} );
     127
     128        bool typesCompatibleIgnoreQualifiers(
     129                const ast::Type *, const ast::Type *, const ast::SymbolTable &,
     130                const ast::TypeEnvironment & env = {} );
     131
    95132        /// creates the type represented by the list of returnVals in a FunctionType. The caller owns the return value.
    96133        Type * extractResultType( FunctionType * functionType );
     134        /// Creates or extracts the type represented by the list of returns in a `FunctionType`.
     135        ast::ptr<ast::Type> extractResultType( const ast::FunctionType * func );
    97136
    98137        // in CommonType.cc
    99         Type *commonType( Type *type1, Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars );
     138        Type * commonType( Type * type1, Type * type2, bool widenFirst, bool widenSecond, const SymTab::Indexer & indexer, TypeEnvironment & env, const OpenVarSet & openVars );
     139        ast::ptr< ast::Type > commonType(
     140                const ast::ptr< ast::Type > & type1, const ast::ptr< ast::Type > & type2, WidenMode widen,
     141                const ast::SymbolTable & symtab, ast::TypeEnvironment & env, const ast::OpenVarSet & open );
    100142
    101143        // in PolyCost.cc
    102         int polyCost( Type *type, const TypeEnvironment &env, const SymTab::Indexer &indexer );
     144        int polyCost( Type * type, const TypeEnvironment & env, const SymTab::Indexer & indexer );
     145        int polyCost(
     146                const ast::Type * type, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
     147
     148        // in SpecCost.cc
     149        int specCost( Type * type );
     150        int specCost( const ast::Type * type );
    103151
    104152        // in Occurs.cc
    105         bool occurs( Type *type, std::string varName, const TypeEnvironment &env );
     153        bool occurs( const Type * type, const std::string & varName, const TypeEnvironment & env );
     154        // new AST version in TypeEnvironment.cpp (only place it was used in old AST)
     155
     156        template<typename Iter>
     157        bool occursIn( Type* ty, Iter begin, Iter end, const TypeEnvironment & env ) {
     158                while ( begin != end ) {
     159                        if ( occurs( ty, *begin, env ) ) return true;
     160                        ++begin;
     161                }
     162                return false;
     163        }
    106164
    107165        // in AlternativeFinder.cc
    108166        void referenceToRvalueConversion( Expression *& expr, Cost & cost );
    109 
    110         // flatten tuple type into list of types
     167        // in CandidateFinder.cpp
     168        const ast::Expr * referenceToRvalueConversion( const ast::Expr * expr, Cost & cost );
     169
     170        /// flatten tuple type into list of types
    111171        template< typename OutputIterator >
    112172        void flatten( Type * type, OutputIterator out ) {
     
    119179                }
    120180        }
     181
     182        /// flatten tuple type into existing list of types
     183        static inline void flatten(
     184                const ast::Type * type, std::vector< ast::ptr< ast::Type > > & out
     185        ) {
     186                if ( auto tupleType = dynamic_cast< const ast::TupleType * >( type ) ) {
     187                        for ( const ast::Type * t : tupleType->types ) {
     188                                flatten( t, out );
     189                        }
     190                } else {
     191                        out.emplace_back( type );
     192                }
     193        }
     194
     195        /// flatten tuple type into list of types
     196        static inline std::vector< ast::ptr< ast::Type > > flatten( const ast::Type * type ) {
     197                std::vector< ast::ptr< ast::Type > > out;
     198                out.reserve( type->size() );
     199                flatten( type, out );
     200                return out;
     201        }
     202
     203        // in TypeEnvironment.cc
     204        bool isFtype( const Type * type );
    121205} // namespace ResolvExpr
     206
     207namespace ast {
     208        // in TypeEnvironment.cpp
     209        bool isFtype( const ast::Type * type );
     210} // namespace ast
    122211
    123212// Local Variables: //
Note: See TracChangeset for help on using the changeset viewer.