Changeset 6e1e2d0 for src


Ignore:
Timestamp:
May 1, 2023, 4:19:09 PM (2 years ago)
Author:
caparsons <caparson@…>
Branches:
ADT, ast-experimental, master
Children:
c083c3d
Parents:
a50fdfb (diff), 985b624 (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:

resolved merge conflicts

Location:
src
Files:
6 added
45 edited

Legend:

Unmodified
Added
Removed
  • src/AST/Attribute.hpp

    ra50fdfb r6e1e2d0  
    2727class Expr;
    2828
     29/// An entry in an attribute list: `__attribute__(( ... ))`
    2930class Attribute final : public Node {
    3031public:
  • src/AST/Convert.cpp

    ra50fdfb r6e1e2d0  
    559559                auto stmt = new SuspendStmt();
    560560                stmt->then   = get<CompoundStmt>().accept1( node->then   );
    561                 switch(node->type) {
     561                switch (node->kind) {
    562562                        case ast::SuspendStmt::None     : stmt->type = SuspendStmt::None     ; break;
    563563                        case ast::SuspendStmt::Coroutine: stmt->type = SuspendStmt::Coroutine; break;
     
    16951695                        GET_ACCEPT_V(attributes, Attribute),
    16961696                        { old->get_funcSpec().val },
    1697                         old->type->isVarArgs
     1697                        (old->type->isVarArgs) ? ast::VariableArgs : ast::FixedArgs
    16981698                };
    16991699
     
    20012001                        GET_ACCEPT_1(else_, Stmt),
    20022002                        GET_ACCEPT_V(initialization, Stmt),
    2003                         old->isDoWhile,
     2003                        (old->isDoWhile) ? ast::DoWhile : ast::While,
    20042004                        GET_LABELS_V(old->labels)
    20052005                );
     
    21432143        virtual void visit( const SuspendStmt * old ) override final {
    21442144                if ( inCache( old ) ) return;
    2145                 ast::SuspendStmt::Type type;
     2145                ast::SuspendStmt::Kind type;
    21462146                switch (old->type) {
    21472147                        case SuspendStmt::Coroutine: type = ast::SuspendStmt::Coroutine; break;
  • src/AST/Decl.cpp

    ra50fdfb r6e1e2d0  
    5757        std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    5858        CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage,
    59         std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)
     59        std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, ArgumentFlag isVarArgs )
    6060: DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ),
    6161        type_params(std::move(forall)), assertions(),
    6262        params(std::move(params)), returns(std::move(returns)), stmts( stmts ) {
    63         FunctionType * ftype = new FunctionType(static_cast<ArgumentFlag>(isVarArgs));
     63        FunctionType * ftype = new FunctionType( isVarArgs );
    6464        for (auto & param : this->params) {
    6565                ftype->params.emplace_back(param->get_type());
     
    8181        std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    8282        CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage,
    83         std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)
     83        std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, ArgumentFlag isVarArgs )
    8484: DeclWithType( location, name, storage, linkage, std::move(attrs), fs ),
    8585                type_params( std::move( forall) ), assertions( std::move( assertions ) ),
    8686                params( std::move(params) ), returns( std::move(returns) ),
    8787                type( nullptr ), stmts( stmts ) {
    88         FunctionType * type = new FunctionType( (isVarArgs) ? VariableArgs : FixedArgs );
     88        FunctionType * type = new FunctionType( isVarArgs );
    8989        for ( auto & param : this->params ) {
    9090                type->params.emplace_back( param->get_type() );
  • src/AST/Decl.hpp

    ra50fdfb r6e1e2d0  
    1010// Created On       : Thu May 9 10:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Nov 24  9:44:00 2022
    13 // Update Count     : 34
     12// Last Modified On : Wed Apr  5 10:42:00 2023
     13// Update Count     : 35
    1414//
    1515
     
    122122};
    123123
     124/// Function variable arguments flag
     125enum ArgumentFlag { FixedArgs, VariableArgs };
     126
    124127/// Object declaration `int foo()`
    125128class FunctionDecl : public DeclWithType {
     
    144147                std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    145148                CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::Cforall,
    146                 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
     149                std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, ArgumentFlag isVarArgs = FixedArgs );
    147150
    148151        FunctionDecl( const CodeLocation & location, const std::string & name,
     
    150153                std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    151154                CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::Cforall,
    152                 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
     155                std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, ArgumentFlag isVarArgs = FixedArgs );
    153156
    154157        const Type * get_type() const override;
     
    313316public:
    314317        bool isTyped; // isTyped indicated if the enum has a declaration like:
    315         // enum (type_optional) Name {...} 
     318        // enum (type_optional) Name {...}
    316319        ptr<Type> base; // if isTyped == true && base.get() == nullptr, it is a "void" type enum
    317320        enum class EnumHiding { Visible, Hide } hide;
     
    371374};
    372375
     376/// Assembly declaration: `asm ... ( "..." : ... )`
    373377class AsmDecl : public Decl {
    374378public:
  • src/AST/Expr.hpp

    ra50fdfb r6e1e2d0  
    254254};
    255255
     256/// A name qualified by a namespace or type.
    256257class QualifiedNameExpr final : public Expr {
    257258public:
     
    259260        std::string name;
    260261
    261         QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n ) 
     262        QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n )
    262263        : Expr( loc ), type_decl( d ), name( n ) {}
    263264
     
    621622};
    622623
     624/// A name that refers to a generic dimension parameter.
    623625class DimensionExpr final : public Expr {
    624626public:
     
    910912};
    911913
    912 
    913914}
    914915
  • src/AST/Init.hpp

    ra50fdfb r6e1e2d0  
    117117        ptr<Init> init;
    118118
    119         ConstructorInit( 
     119        ConstructorInit(
    120120                const CodeLocation & loc, const Stmt * ctor, const Stmt * dtor, const Init * init )
    121121        : Init( loc, MaybeConstruct ), ctor( ctor ), dtor( dtor ), init( init ) {}
  • src/AST/Inspect.cpp

    ra50fdfb r6e1e2d0  
    1010// Created On       : Fri Jun 24 13:16:31 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Oct  3 11:04:00 2022
    13 // Update Count     : 3
     12// Last Modified On : Fri Apr 14 15:09:00 2023
     13// Update Count     : 4
    1414//
    1515
     
    168168}
    169169
     170bool isUnnamedBitfield( const ast::ObjectDecl * obj ) {
     171        return obj && obj->name.empty() && obj->bitfieldWidth;
     172}
     173
    170174} // namespace ast
  • src/AST/Inspect.hpp

    ra50fdfb r6e1e2d0  
    1010// Created On       : Fri Jun 24 13:16:31 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Sep 22 13:44:00 2022
    13 // Update Count     : 2
     12// Last Modified On : Fri Apr 14 15:09:00 2023
     13// Update Count     : 3
    1414//
    1515
     
    3838const ApplicationExpr * isIntrinsicCallExpr( const Expr * expr );
    3939
     40/// Returns true if obj's name is the empty string and it has a bitfield width.
     41bool isUnnamedBitfield( const ObjectDecl * obj );
     42
    4043}
  • src/AST/Pass.impl.hpp

    ra50fdfb r6e1e2d0  
    20752075        if ( __visit_children() ) {
    20762076                maybe_accept( node, &TupleType::types );
    2077                 maybe_accept( node, &TupleType::members );
    20782077        }
    20792078
  • src/AST/Print.cpp

    ra50fdfb r6e1e2d0  
    766766        virtual const ast::Stmt * visit( const ast::SuspendStmt * node ) override final {
    767767                os << "Suspend Statement";
    768                 switch (node->type) {
    769                         case ast::SuspendStmt::None     : os << " with implicit target"; break;
    770                         case ast::SuspendStmt::Generator: os << " for generator"; break;
    771                         case ast::SuspendStmt::Coroutine: os << " for coroutine"; break;
     768                switch (node->kind) {
     769                case ast::SuspendStmt::None     : os << " with implicit target"; break;
     770                case ast::SuspendStmt::Generator: os << " for generator"; break;
     771                case ast::SuspendStmt::Coroutine: os << " for coroutine"; break;
    772772                }
    773773                os << endl;
  • src/AST/Stmt.hpp

    ra50fdfb r6e1e2d0  
    1010// Created On       : Wed May  8 13:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Apr 20 14:34:00 2022
    13 // Update Count     : 36
     12// Last Modified On : Wed Apr  5 10:34:00 2023
     13// Update Count     : 37
    1414//
    1515
     
    205205};
    206206
     207// A while loop or a do-while loop:
     208enum WhileDoKind { While, DoWhile };
     209
    207210// While loop: while (...) ... else ... or do ... while (...) else ...;
    208211class WhileDoStmt final : public Stmt {
     
    212215        ptr<Stmt> else_;
    213216        std::vector<ptr<Stmt>> inits;
    214         bool isDoWhile;
     217        WhileDoKind isDoWhile;
    215218
    216219        WhileDoStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body,
    217                                  const std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, const std::vector<Label> && labels = {} )
     220                                 const std::vector<ptr<Stmt>> && inits, WhileDoKind isDoWhile = While, const std::vector<Label> && labels = {} )
    218221                : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(nullptr), inits(std::move(inits)), isDoWhile(isDoWhile) {}
    219222
    220223        WhileDoStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body, const Stmt * else_,
    221                                  const std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, const std::vector<Label> && labels = {} )
     224                                 const std::vector<ptr<Stmt>> && inits, WhileDoKind isDoWhile = While, const std::vector<Label> && labels = {} )
    222225                : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(else_), inits(std::move(inits)), isDoWhile(isDoWhile) {}
    223226
     
    364367  public:
    365368        ptr<CompoundStmt> then;
    366         enum Type { None, Coroutine, Generator } type = None;
    367 
    368         SuspendStmt( const CodeLocation & loc, const CompoundStmt * then, Type type, const std::vector<Label> && labels = {} )
    369                 : Stmt(loc, std::move(labels)), then(then), type(type) {}
     369        enum Kind { None, Coroutine, Generator } kind = None;
     370
     371        SuspendStmt( const CodeLocation & loc, const CompoundStmt * then, Kind kind, const std::vector<Label> && labels = {} )
     372                : Stmt(loc, std::move(labels)), then(then), kind(kind) {}
    370373
    371374        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     
    424427};
    425428
     429// Clause in a waitfor statement: waitfor (..., ...) ...
    426430class WaitForClause final : public WhenClause {
    427431  public:
     
    527531        MUTATE_FRIEND
    528532};
     533
    529534} // namespace ast
    530535
  • src/AST/SymbolTable.cpp

    ra50fdfb r6e1e2d0  
    260260void SymbolTable::addId( const DeclWithType * decl, const Expr * baseExpr ) {
    261261        // default handling of conflicts is to raise an error
    262         addId( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
     262        addIdCommon( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
    263263}
    264264
    265265void SymbolTable::addDeletedId( const DeclWithType * decl, const Decl * deleter ) {
    266266        // default handling of conflicts is to raise an error
    267         addId( decl, OnConflict::error(), nullptr, deleter );
     267        addIdCommon( decl, OnConflict::error(), nullptr, deleter );
    268268}
    269269
     
    677677}
    678678
    679 void SymbolTable::addId(
    680                 const DeclWithType * decl, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,
    681                 const Decl * deleter ) {
     679void SymbolTable::addIdCommon(
     680                const DeclWithType * decl, SymbolTable::OnConflict handleConflicts,
     681                const Expr * baseExpr, const Decl * deleter ) {
    682682        SpecialFunctionKind kind = getSpecialFunctionKind(decl->name);
    683683        if (kind == NUMBER_OF_KINDS) { // not a special decl
    684                 addId(decl, decl->name, idTable, handleConflicts, baseExpr, deleter);
     684                addIdToTable(decl, decl->name, idTable, handleConflicts, baseExpr, deleter);
    685685        }
    686686        else {
     
    695695                        assertf(false, "special decl with non-function type");
    696696                }
    697                 addId(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter);
    698         }
    699 }
    700 
    701 void SymbolTable::addId(
    702                 const DeclWithType * decl, const std::string & lookupKey, IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,
    703                 const Decl * deleter ) {
     697                addIdToTable(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter);
     698        }
     699}
     700
     701void SymbolTable::addIdToTable(
     702                const DeclWithType * decl, const std::string & lookupKey,
     703                IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts,
     704                const Expr * baseExpr, const Decl * deleter ) {
    704705        ++*stats().add_calls;
    705706        const std::string &name = decl->name;
     
    778779void SymbolTable::addMembers(
    779780                const AggregateDecl * aggr, const Expr * expr, SymbolTable::OnConflict handleConflicts ) {
    780         for ( const Decl * decl : aggr->members ) {
    781                 if ( auto dwt = dynamic_cast< const DeclWithType * >( decl ) ) {
    782                         addId( dwt, handleConflicts, expr );
    783                         if ( dwt->name == "" ) {
    784                                 const Type * t = dwt->get_type()->stripReferences();
    785                                 if ( auto rty = dynamic_cast<const BaseInstType *>( t ) ) {
    786                                         if ( ! dynamic_cast<const StructInstType *>(rty)
    787                                                 && ! dynamic_cast<const UnionInstType *>(rty) ) continue;
    788                                         ResolvExpr::Cost cost = ResolvExpr::Cost::zero;
    789                                         ast::ptr<ast::TypeSubstitution> tmp = expr->env;
    790                                         expr = mutate_field(expr, &Expr::env, nullptr);
    791                                         const Expr * base = ResolvExpr::referenceToRvalueConversion( expr, cost );
    792                                         base = mutate_field(base, &Expr::env, tmp);
    793 
    794                                         addMembers(
    795                                                 rty->aggr(), new MemberExpr{ base->location, dwt, base }, handleConflicts );
    796                                 }
    797                         }
     781        for ( const ptr<Decl> & decl : aggr->members ) {
     782                auto dwt = decl.as<DeclWithType>();
     783                if ( nullptr == dwt ) continue;
     784                addIdCommon( dwt, handleConflicts, expr );
     785                // Inline through unnamed struct/union members.
     786                if ( "" != dwt->name ) continue;
     787                const Type * t = dwt->get_type()->stripReferences();
     788                if ( auto rty = dynamic_cast<const BaseInstType *>( t ) ) {
     789                        if ( ! dynamic_cast<const StructInstType *>(rty)
     790                                && ! dynamic_cast<const UnionInstType *>(rty) ) continue;
     791                        ResolvExpr::Cost cost = ResolvExpr::Cost::zero;
     792                        ast::ptr<ast::TypeSubstitution> tmp = expr->env;
     793                        expr = mutate_field(expr, &Expr::env, nullptr);
     794                        const Expr * base = ResolvExpr::referenceToRvalueConversion( expr, cost );
     795                        base = mutate_field(base, &Expr::env, tmp);
     796
     797                        addMembers(
     798                                rty->aggr(), new MemberExpr{ base->location, dwt, base }, handleConflicts );
    798799                }
    799800        }
  • src/AST/SymbolTable.hpp

    ra50fdfb r6e1e2d0  
    192192
    193193        /// common code for addId, addDeletedId, etc.
    194         void addId(
    195                 const DeclWithType * decl, OnConflict handleConflicts, const Expr * baseExpr = nullptr,
    196                 const Decl * deleter = nullptr );
     194        void addIdCommon(
     195                const DeclWithType * decl, OnConflict handleConflicts,
     196                const Expr * baseExpr = nullptr, const Decl * deleter = nullptr );
    197197
    198198        /// common code for addId when special decls are placed into separate tables
    199         void addId(
    200                 const DeclWithType * decl, const std::string & lookupKey, IdTable::Ptr & idTable, OnConflict handleConflicts,
     199        void addIdToTable(
     200                const DeclWithType * decl, const std::string & lookupKey,
     201                IdTable::Ptr & idTable, OnConflict handleConflicts,
    201202                const Expr * baseExpr = nullptr, const Decl * deleter = nullptr);
    202        
     203
    203204        /// adds all of the members of the Aggregate (addWith helper)
    204205        void addMembers( const AggregateDecl * aggr, const Expr * expr, OnConflict handleConflicts );
  • src/AST/Type.cpp

    ra50fdfb r6e1e2d0  
    1010// Created On       : Mon May 13 15:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Nov 24  9:49:00 2022
    13 // Update Count     : 6
     12// Last Modified On : Thu Apr  6 15:59:00 2023
     13// Update Count     : 7
    1414//
    1515
     
    199199
    200200TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q )
    201 : Type( q ), types( std::move(ts) ), members() {
    202         // This constructor is awkward. `TupleType` needs to contain objects so that members can be
    203         // named, but members without initializer nodes end up getting constructors, which breaks
    204         // things. This happens because the object decls have to be visited so that their types are
    205         // kept in sync with the types listed here. Ultimately, the types listed here should perhaps
    206         // be eliminated and replaced with a list-view over members. The temporary solution is to
    207         // make a `ListInit` with `maybeConstructed = false`, so when the object is visited it is not
    208         // constructed. Potential better solutions include:
    209         //   a) Separate `TupleType` from its declarations, into `TupleDecl` and `Tuple{Inst?}Type`,
    210         //      similar to the aggregate types.
    211         //   b) Separate initializer nodes better, e.g. add a `MaybeConstructed` node that is replaced
    212         //      by `genInit`, rather than the current boolean flag.
    213         members.reserve( types.size() );
    214         for ( const Type * ty : types ) {
    215                 members.emplace_back( new ObjectDecl{
    216                         CodeLocation(), "", ty, new ListInit( CodeLocation(), {}, {}, NoConstruct ),
    217                         Storage::Classes{}, Linkage::Cforall } );
    218         }
    219 }
     201: Type( q ), types( std::move(ts) ) {}
    220202
    221203bool isUnboundType(const Type * type) {
  • src/AST/Type.hpp

    ra50fdfb r6e1e2d0  
    1010// Created On       : Thu May 9 10:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Nov 24  9:47:00 2022
    13 // Update Count     : 8
     12// Last Modified On : Thu Apr  6 15:58:00 2023
     13// Update Count     : 9
    1414//
    1515
     
    265265};
    266266
    267 /// Function variable arguments flag
    268 enum ArgumentFlag { FixedArgs, VariableArgs };
    269 
    270267/// Type of a function `[R1, R2](*)(P1, P2, P3)`
    271268class FunctionType final : public Type {
     
    460457public:
    461458        std::vector<ptr<Type>> types;
    462         std::vector<ptr<Decl>> members;
    463459
    464460        TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q = {} );
  • src/Common/CodeLocationTools.cpp

    ra50fdfb r6e1e2d0  
    210210
    211211struct LeafKindVisitor : public ast::Visitor {
    212         LeafKind kind;
     212        LeafKind result;
    213213
    214214#define VISIT(node_type, return_type) \
    215215        const ast::return_type * visit( const ast::node_type * ) final { \
    216                 kind = LeafKind::node_type; \
     216                result = LeafKind::node_type; \
    217217                return nullptr; \
    218218        }
     
    224224
    225225LeafKind get_leaf_kind( ast::Node const * node ) {
    226         LeafKindVisitor visitor;
    227         node->accept( visitor );
    228         return visitor.kind;
     226        return ast::Pass<LeafKindVisitor>::read( node );
    229227}
    230228
  • src/Common/Iterate.hpp

    ra50fdfb r6e1e2d0  
    2020#include <iterator>
    2121
    22 // it's nice to actually be able to increment iterators by an arbitrary amount
     22// Returns an iterator that is it advanced n times.
    2323template< class InputIt, class Distance >
    2424InputIt operator+( InputIt it, Distance n ) {
     
    5050
    5151// -----------------------------------------------------------------------------
     52// Helper struct and function to support
     53// for ( val_and_index : enumerate( container ) ) {}
     54// which iterates through the container and tracks the index as well.
     55
    5256template< typename T >
    5357struct enumerate_t {
     
    109113
    110114// -----------------------------------------------------------------------------
     115// Helper function to transform one iterable container into another.
     116
    111117template< typename OutType, typename Range, typename Functor >
    112118OutType map_range( const Range& range, Functor&& functor ) {
     
    206212// Helper struct and function to support
    207213// for ( val : lazy_map( container1, f ) ) {}
    208 // syntax to have a for each that iterates a container, mapping each element by applying f
     214// syntax to have a for each that iterates a container,
     215// mapping each element by applying f.
     216
    209217template< typename T, typename Func >
    210218struct lambda_iterate_t {
  • src/CompilationState.cc

    ra50fdfb r6e1e2d0  
    99// Author           : Rob Schluntz
    1010// Created On       : Mon Ju1 30 10:47:01 2018
    11 // Last Modified By : Henry Xue
    12 // Last Modified On : Tue Jul 20 04:27:35 2021
    13 // Update Count     : 5
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Apr 10 19:12:50 2023
     13// Update Count     : 6
    1414//
    1515
     
    2727        expraltp = false,
    2828        genericsp = false,
     29        invariant = false,
    2930        libcfap = false,
    3031        nopreludep = false,
  • src/CompilationState.h

    ra50fdfb r6e1e2d0  
    99// Author           : Rob Schluntz
    1010// Created On       : Mon Ju1 30 10:47:01 2018
    11 // Last Modified By : Henry Xue
    12 // Last Modified On : Tue Jul 20 04:27:35 2021
    13 // Update Count     : 5
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Apr 10 19:12:53 2023
     13// Update Count     : 6
    1414//
    1515
     
    2626        expraltp,
    2727        genericsp,
     28        invariant,
    2829        libcfap,
    2930        nopreludep,
  • src/Concurrency/KeywordsNew.cpp

    ra50fdfb r6e1e2d0  
    779779
    780780const ast::Stmt * SuspendKeyword::postvisit( const ast::SuspendStmt * stmt ) {
    781         switch ( stmt->type ) {
     781        switch ( stmt->kind ) {
    782782        case ast::SuspendStmt::None:
    783783                // Use the context to determain the implicit target.
  • src/InitTweak/FixInitNew.cpp

    ra50fdfb r6e1e2d0  
    1414#include <utility>                     // for pair
    1515
     16#include "AST/DeclReplacer.hpp"
     17#include "AST/Expr.hpp"
    1618#include "AST/Inspect.hpp"             // for getFunction, getPointerBase, g...
     19#include "AST/Node.hpp"
     20#include "AST/Pass.hpp"
     21#include "AST/Print.hpp"
     22#include "AST/SymbolTable.hpp"
     23#include "AST/Type.hpp"
    1724#include "CodeGen/GenType.h"           // for genPrettyType
    1825#include "CodeGen/OperatorTable.h"
    19 #include "Common/CodeLocationTools.hpp"
    2026#include "Common/PassVisitor.h"        // for PassVisitor, WithStmtsToAdd
    2127#include "Common/SemanticError.h"      // for SemanticError
     
    2834#include "ResolvExpr/Unify.h"          // for typesCompatible
    2935#include "SymTab/Autogen.h"            // for genImplicitCall
     36#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    3037#include "SymTab/Indexer.h"            // for Indexer
    3138#include "SymTab/Mangler.h"            // for Mangler
     
    4552#include "Validate/FindSpecialDecls.h" // for dtorStmt, dtorStructDestroy
    4653
    47 #include "AST/Expr.hpp"
    48 #include "AST/Node.hpp"
    49 #include "AST/Pass.hpp"
    50 #include "AST/Print.hpp"
    51 #include "AST/SymbolTable.hpp"
    52 #include "AST/Type.hpp"
    53 #include "AST/DeclReplacer.hpp"
    54 
    5554extern bool ctordtorp; // print all debug
    5655extern bool ctorp; // print ctor debug
     
    6362namespace InitTweak {
    6463namespace {
     64
     65        // Shallow copy the pointer list for return.
     66        std::vector<ast::ptr<ast::TypeDecl>> getGenericParams( const ast::Type * t ) {
     67                if ( auto inst = dynamic_cast<const ast::StructInstType *>( t ) ) {
     68                        return inst->base->params;
     69                }
     70                if ( auto inst = dynamic_cast<const ast::UnionInstType *>( t ) ) {
     71                        return inst->base->params;
     72                }
     73                return {};
     74        }
     75
     76        /// Given type T, generate type of default ctor/dtor, i.e. function type void (*) (T &).
     77        ast::FunctionDecl * genDefaultFunc(
     78                        const CodeLocation loc,
     79                        const std::string fname,
     80                        const ast::Type * paramType,
     81                        bool maybePolymorphic = true) {
     82                std::vector<ast::ptr<ast::TypeDecl>> typeParams;
     83                if ( maybePolymorphic ) typeParams = getGenericParams( paramType );
     84                auto dstParam = new ast::ObjectDecl( loc,
     85                        "_dst",
     86                        new ast::ReferenceType( paramType ),
     87                        nullptr,
     88                        {},
     89                        ast::Linkage::Cforall
     90                );
     91                return new ast::FunctionDecl( loc,
     92                        fname,
     93                        std::move(typeParams),
     94                        {dstParam},
     95                        {},
     96                        new ast::CompoundStmt(loc),
     97                        {},
     98                        ast::Linkage::Cforall
     99                );
     100        }
     101
    65102        struct SelfAssignChecker {
    66103                void previsit( const ast::ApplicationExpr * appExpr );
     
    121158                void previsit( const ast::FunctionDecl * ) { visit_children = false; }
    122159
    123           protected:
     160        protected:
    124161                ObjectSet curVars;
    125162        };
     
    202239
    203240                SemanticErrorException errors;
    204           private:
     241        private:
    205242                template< typename... Params >
    206243                void emit( CodeLocation, const Params &... params );
     
    288325                static UniqueName dtorNamer( "__cleanup_dtor" );
    289326                std::string name = dtorNamer.newName();
    290                 ast::FunctionDecl * dtorFunc = SymTab::genDefaultFunc( loc, name, objDecl->type->stripReferences(), false );
     327                ast::FunctionDecl * dtorFunc = genDefaultFunc( loc, name, objDecl->type->stripReferences(), false );
    291328                stmtsToAdd.push_back( new ast::DeclStmt(loc, dtorFunc ) );
    292329
     
    10801117        void InsertDtors::previsit( const ast::BranchStmt * stmt ) {
    10811118                switch( stmt->kind ) {
    1082                   case ast::BranchStmt::Continue:
    1083                   case ast::BranchStmt::Break:
     1119                case ast::BranchStmt::Continue:
     1120                case ast::BranchStmt::Break:
    10841121                        // could optimize the break/continue case, because the S_L-S_G check is unnecessary (this set should
    10851122                        // always be empty), but it serves as a small sanity check.
    1086                   case ast::BranchStmt::Goto:
     1123                case ast::BranchStmt::Goto:
    10871124                        handleGoto( stmt );
    10881125                        break;
    1089                   default:
     1126                default:
    10901127                        assert( false );
    10911128                } // switch
     
    13121349                // xxx - functions returning ast::ptr seems wrong...
    13131350                auto res = ResolvExpr::findVoidExpression( untypedExpr, { symtab, transUnit().global } );
    1314                 // Fix CodeLocation (at least until resolver is fixed).
    1315                 auto fix = localFillCodeLocations( untypedExpr->location, res.release() );
    1316                 return strict_dynamic_cast<const ast::Expr *>( fix );
     1351                return res.release();
    13171352        }
    13181353
  • src/InitTweak/GenInit.cc

    ra50fdfb r6e1e2d0  
    3939#include "ResolvExpr/Resolver.h"
    4040#include "SymTab/Autogen.h"            // for genImplicitCall
     41#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    4142#include "SymTab/Mangler.h"            // for Mangler
    4243#include "SynTree/LinkageSpec.h"       // for isOverridable, C
  • src/Parser/DeclarationNode.cc

    ra50fdfb r6e1e2d0  
    1010// Created On       : Sat May 16 12:34:05 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Apr  4 10:28:00 2023
    13 // Update Count     : 1392
     12// Last Modified On : Thr Apr 20 11:46:00 2023
     13// Update Count     : 1393
    1414//
     15
     16#include "DeclarationNode.h"
    1517
    1618#include <cassert>                 // for assert, assertf, strict_dynamic_cast
     
    3436#include "Common/UniqueName.h"     // for UniqueName
    3537#include "Common/utility.h"        // for maybeClone
    36 #include "Parser/ParseNode.h"      // for DeclarationNode, ExpressionNode
     38#include "Parser/ExpressionNode.h" // for ExpressionNode
     39#include "Parser/InitializerNode.h"// for InitializerNode
     40#include "Parser/StatementNode.h"  // for StatementNode
    3741#include "TypeData.h"              // for TypeData, TypeData::Aggregate_t
    3842#include "TypedefTable.h"          // for TypedefTable
     
    9991003}
    10001004
    1001 void buildList( const DeclarationNode * firstNode,
     1005// If a typedef wraps an anonymous declaration, name the inner declaration
     1006// so it has a consistent name across translation units.
     1007static void nameTypedefedDecl(
     1008                DeclarationNode * innerDecl,
     1009                const DeclarationNode * outerDecl ) {
     1010        TypeData * outer = outerDecl->type;
     1011        assert( outer );
     1012        // First make sure this is a typedef:
     1013        if ( outer->kind != TypeData::Symbolic || !outer->symbolic.isTypedef ) {
     1014                return;
     1015        }
     1016        TypeData * inner = innerDecl->type;
     1017        assert( inner );
     1018        // Always clear any CVs associated with the aggregate:
     1019        inner->qualifiers.reset();
     1020        // Handle anonymous aggregates: typedef struct { int i; } foo
     1021        if ( inner->kind == TypeData::Aggregate && inner->aggregate.anon ) {
     1022                delete inner->aggregate.name;
     1023                inner->aggregate.name = new string( "__anonymous_" + *outerDecl->name );
     1024                inner->aggregate.anon = false;
     1025                assert( outer->base );
     1026                delete outer->base->aggInst.aggregate->aggregate.name;
     1027                outer->base->aggInst.aggregate->aggregate.name = new string( "__anonymous_" + *outerDecl->name );
     1028                outer->base->aggInst.aggregate->aggregate.anon = false;
     1029                outer->base->aggInst.aggregate->qualifiers.reset();
     1030        // Handle anonymous enumeration: typedef enum { A, B, C } foo
     1031        } else if ( inner->kind == TypeData::Enum && inner->enumeration.anon ) {
     1032                delete inner->enumeration.name;
     1033                inner->enumeration.name = new string( "__anonymous_" + *outerDecl->name );
     1034                inner->enumeration.anon = false;
     1035                assert( outer->base );
     1036                delete outer->base->aggInst.aggregate->enumeration.name;
     1037                outer->base->aggInst.aggregate->enumeration.name = new string( "__anonymous_" + *outerDecl->name );
     1038                outer->base->aggInst.aggregate->enumeration.anon = false;
     1039                // No qualifiers.reset() here.
     1040        }
     1041}
     1042
     1043// This code handles a special issue with the attribute transparent_union.
     1044//
     1045//    typedef union U { int i; } typedef_name __attribute__(( aligned(16) )) __attribute__(( transparent_union ))
     1046//
     1047// Here the attribute aligned goes with the typedef_name, so variables declared of this type are
     1048// aligned.  However, the attribute transparent_union must be moved from the typedef_name to
     1049// alias union U.  Currently, this is the only know attribute that must be moved from typedef to
     1050// alias.
     1051static void moveUnionAttribute( ast::Decl * decl, ast::UnionDecl * unionDecl ) {
     1052        if ( auto typedefDecl = dynamic_cast<ast::TypedefDecl *>( decl ) ) {
     1053                // Is the typedef alias a union aggregate?
     1054                if ( nullptr == unionDecl ) return;
     1055
     1056                // If typedef is an alias for a union, then its alias type was hoisted above and remembered.
     1057                if ( auto unionInstType = typedefDecl->base.as<ast::UnionInstType>() ) {
     1058                        auto instType = ast::mutate( unionInstType );
     1059                        // Remove all transparent_union attributes from typedef and move to alias union.
     1060                        for ( auto attr = instType->attributes.begin() ; attr != instType->attributes.end() ; ) {
     1061                                assert( *attr );
     1062                                if ( (*attr)->name == "transparent_union" || (*attr)->name == "__transparent_union__" ) {
     1063                                        unionDecl->attributes.emplace_back( attr->release() );
     1064                                        attr = instType->attributes.erase( attr );
     1065                                } else {
     1066                                        attr++;
     1067                                }
     1068                        }
     1069                        typedefDecl->base = instType;
     1070                }
     1071        }
     1072}
     1073
     1074// Get the non-anonymous name of the instance type of the declaration,
     1075// if one exists.
     1076static const std::string * getInstTypeOfName( ast::Decl * decl ) {
     1077        if ( auto dwt = dynamic_cast<ast::DeclWithType *>( decl ) ) {
     1078                if ( auto aggr = dynamic_cast<ast::BaseInstType const *>( dwt->get_type() ) ) {
     1079                        if ( aggr->name.find("anonymous") == std::string::npos ) {
     1080                                return &aggr->name;
     1081                        }
     1082                }
     1083        }
     1084        return nullptr;
     1085}
     1086
     1087void buildList( DeclarationNode * firstNode,
    10021088                std::vector<ast::ptr<ast::Decl>> & outputList ) {
    10031089        SemanticErrorException errors;
    10041090        std::back_insert_iterator<std::vector<ast::ptr<ast::Decl>>> out( outputList );
    10051091
    1006         for ( const DeclarationNode * cur = firstNode; cur; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ) ) {
     1092        for ( const DeclarationNode * cur = firstNode ; cur ; cur = strict_next( cur ) ) {
    10071093                try {
    1008                         bool extracted = false, anon = false;
    1009                         ast::AggregateDecl * unionDecl = nullptr;
     1094                        bool extracted_named = false;
     1095                        ast::UnionDecl * unionDecl = nullptr;
    10101096
    10111097                        if ( DeclarationNode * extr = cur->extractAggregate() ) {
    1012                                 // Handle the case where a SUE declaration is contained within an object or type declaration.
    1013 
    10141098                                assert( cur->type );
    1015                                 // Replace anonymous SUE name with typedef name to prevent anonymous naming problems across translation units.
    1016                                 if ( cur->type->kind == TypeData::Symbolic && cur->type->symbolic.isTypedef ) {
    1017                                         assert( extr->type );
    1018                                         // Handle anonymous aggregates: typedef struct { int i; } foo
    1019                                         extr->type->qualifiers.reset();         // clear any CVs associated with the aggregate
    1020                                         if ( extr->type->kind == TypeData::Aggregate && extr->type->aggregate.anon ) {
    1021                                                 delete extr->type->aggregate.name;
    1022                                                 extr->type->aggregate.name = new string( "__anonymous_" + *cur->name );
    1023                                                 extr->type->aggregate.anon = false;
    1024                                                 assert( cur->type->base );
    1025                                                 if ( cur->type->base ) {
    1026                                                         delete cur->type->base->aggInst.aggregate->aggregate.name;
    1027                                                         cur->type->base->aggInst.aggregate->aggregate.name = new string( "__anonymous_" + *cur->name );
    1028                                                         cur->type->base->aggInst.aggregate->aggregate.anon = false;
    1029                                                         cur->type->base->aggInst.aggregate->qualifiers.reset();
    1030                                                 } // if
    1031                                         } // if
    1032                                         // Handle anonymous enumeration: typedef enum { A, B, C } foo
    1033                                         if ( extr->type->kind == TypeData::Enum && extr->type->enumeration.anon ) {
    1034                                                 delete extr->type->enumeration.name;
    1035                                                 extr->type->enumeration.name = new string( "__anonymous_" + *cur->name );
    1036                                                 extr->type->enumeration.anon = false;
    1037                                                 assert( cur->type->base );
    1038                                                 if ( cur->type->base ) {
    1039                                                         delete cur->type->base->aggInst.aggregate->enumeration.name;
    1040                                                         cur->type->base->aggInst.aggregate->enumeration.name = new string( "__anonymous_" + *cur->name );
    1041                                                         cur->type->base->aggInst.aggregate->enumeration.anon = false;
    1042                                                 } // if
    1043                                         } // if
    1044                                 } // if
    1045 
    1046                                 ast::Decl * decl = extr->build();
    1047                                 if ( decl ) {
     1099                                nameTypedefedDecl( extr, cur );
     1100
     1101                                if ( ast::Decl * decl = extr->build() ) {
    10481102                                        // Remember the declaration if it is a union aggregate ?
    10491103                                        unionDecl = dynamic_cast<ast::UnionDecl *>( decl );
    10501104
    1051                                         decl->location = cur->location;
    10521105                                        *out++ = decl;
    10531106
    10541107                                        // need to remember the cases where a declaration contains an anonymous aggregate definition
    1055                                         extracted = true;
    10561108                                        assert( extr->type );
    10571109                                        if ( extr->type->kind == TypeData::Aggregate ) {
    10581110                                                // typedef struct { int A } B is the only case?
    1059                                                 anon = extr->type->aggregate.anon;
     1111                                                extracted_named = !extr->type->aggregate.anon;
    10601112                                        } else if ( extr->type->kind == TypeData::Enum ) {
    10611113                                                // typedef enum { A } B is the only case?
    1062                                                 anon = extr->type->enumeration.anon;
     1114                                                extracted_named = !extr->type->enumeration.anon;
     1115                                        } else {
     1116                                                extracted_named = true;
    10631117                                        }
    10641118                                } // if
     
    10661120                        } // if
    10671121
    1068                         ast::Decl * decl = cur->build();
    1069                         if ( decl ) {
    1070                                 if ( auto typedefDecl = dynamic_cast<ast::TypedefDecl *>( decl ) ) {
    1071                                         if ( unionDecl ) {                                      // is the typedef alias a union aggregate ?
    1072                                                 // This code handles a special issue with the attribute transparent_union.
    1073                                                 //
    1074                                                 //    typedef union U { int i; } typedef_name __attribute__(( aligned(16) )) __attribute__(( transparent_union ))
    1075                                                 //
    1076                                                 // Here the attribute aligned goes with the typedef_name, so variables declared of this type are
    1077                                                 // aligned.  However, the attribute transparent_union must be moved from the typedef_name to
    1078                                                 // alias union U.  Currently, this is the only know attribute that must be moved from typedef to
    1079                                                 // alias.
    1080 
    1081                                                 // If typedef is an alias for a union, then its alias type was hoisted above and remembered.
    1082                                                 if ( auto unionInstType = typedefDecl->base.as<ast::UnionInstType>() ) {
    1083                                                         auto instType = ast::mutate( unionInstType );
    1084                                                         // Remove all transparent_union attributes from typedef and move to alias union.
    1085                                                         for ( auto attr = instType->attributes.begin() ; attr != instType->attributes.end() ; ) { // forward order
    1086                                                                 assert( *attr );
    1087                                                                 if ( (*attr)->name == "transparent_union" || (*attr)->name == "__transparent_union__" ) {
    1088                                                                         unionDecl->attributes.emplace_back( attr->release() );
    1089                                                                         attr = instType->attributes.erase( attr );
    1090                                                                 } else {
    1091                                                                         attr++;
    1092                                                                 } // if
    1093                                                         } // for
    1094                                                         typedefDecl->base = instType;
    1095                                                 } // if
    1096                                         } // if
     1122                        if ( ast::Decl * decl = cur->build() ) {
     1123                                moveUnionAttribute( decl, unionDecl );
     1124
     1125                                if ( "" == decl->name && !cur->get_inLine() ) {
     1126                                        // Don't include anonymous declaration for named aggregates,
     1127                                        // but do include them for anonymous aggregates, e.g.:
     1128                                        // struct S {
     1129                                        //   struct T { int x; }; // no anonymous member
     1130                                        //   struct { int y; };   // anonymous member
     1131                                        //   struct T;            // anonymous member
     1132                                        // };
     1133                                        if ( extracted_named ) {
     1134                                                continue;
     1135                                        }
     1136
     1137                                        if ( auto name = getInstTypeOfName( decl ) ) {
     1138                                                // Temporary: warn about anonymous member declarations of named types, since
     1139                                                // this conflicts with the syntax for the forward declaration of an anonymous type.
     1140                                                SemanticWarning( cur->location, Warning::AggrForwardDecl, name->c_str() );
     1141                                        }
    10971142                                } // if
    1098 
    1099                                 // don't include anonymous declaration for named aggregates, but do include them for anonymous aggregates, e.g.:
    1100                                 // struct S {
    1101                                 //   struct T { int x; }; // no anonymous member
    1102                                 //   struct { int y; };   // anonymous member
    1103                                 //   struct T;            // anonymous member
    1104                                 // };
    1105                                 if ( ! (extracted && decl->name == "" && ! anon && ! cur->get_inLine()) ) {
    1106                                         if ( decl->name == "" ) {
    1107                                                 if ( auto dwt = dynamic_cast<ast::DeclWithType *>( decl ) ) {
    1108                                                         if ( auto aggr = dynamic_cast<ast::BaseInstType const *>( dwt->get_type() ) ) {
    1109                                                                 if ( aggr->name.find("anonymous") == std::string::npos ) {
    1110                                                                         if ( ! cur->get_inLine() ) {
    1111                                                                                 // temporary: warn about anonymous member declarations of named types, since
    1112                                                                                 // this conflicts with the syntax for the forward declaration of an anonymous type
    1113                                                                                 SemanticWarning( cur->location, Warning::AggrForwardDecl, aggr->name.c_str() );
    1114                                                                         } // if
    1115                                                                 } // if
    1116                                                         } // if
    1117                                                 } // if
    1118                                         } // if
    1119                                         decl->location = cur->location;
    1120                                         *out++ = decl;
    1121                                 } // if
     1143                                *out++ = decl;
    11221144                        } // if
    1123                 } catch( SemanticErrorException & e ) {
     1145                } catch ( SemanticErrorException & e ) {
    11241146                        errors.append( e );
    11251147                } // try
     
    11321154
    11331155// currently only builds assertions, function parameters, and return values
    1134 void buildList( const DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList ) {
     1156void buildList( DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList ) {
    11351157        SemanticErrorException errors;
    11361158        std::back_insert_iterator<std::vector<ast::ptr<ast::DeclWithType>>> out( outputList );
    11371159
    1138         for ( const DeclarationNode * cur = firstNode; cur; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ) ) {
     1160        for ( const DeclarationNode * cur = firstNode; cur; cur = strict_next( cur ) ) {
    11391161                try {
    11401162                        ast::Decl * decl = cur->build();
    1141                         assert( decl );
     1163                        assertf( decl, "buildList: build for ast::DeclWithType." );
    11421164                        if ( ast::DeclWithType * dwt = dynamic_cast<ast::DeclWithType *>( decl ) ) {
    11431165                                dwt->location = cur->location;
     
    11681190                                );
    11691191                                *out++ = obj;
     1192                        } else {
     1193                                assertf( false, "buildList: Could not convert to ast::DeclWithType." );
    11701194                        } // if
    1171                 } catch( SemanticErrorException & e ) {
     1195                } catch ( SemanticErrorException & e ) {
    11721196                        errors.append( e );
    11731197                } // try
     
    11831207        SemanticErrorException errors;
    11841208        std::back_insert_iterator<std::vector<ast::ptr<ast::Type>>> out( outputList );
    1185         const DeclarationNode * cur = firstNode;
    1186 
    1187         while ( cur ) {
     1209
     1210        for ( const DeclarationNode * cur = firstNode ; cur ; cur = strict_next( cur ) ) {
    11881211                try {
    11891212                        * out++ = cur->buildType();
    1190                 } catch( SemanticErrorException & e ) {
     1213                } catch ( SemanticErrorException & e ) {
    11911214                        errors.append( e );
    11921215                } // try
    1193                 cur = dynamic_cast< DeclarationNode * >( cur->get_next() );
    1194         } // while
     1216        } // for
    11951217
    11961218        if ( ! errors.isEmpty() ) {
  • src/Parser/ExpressionNode.cc

    ra50fdfb r6e1e2d0  
    1313// Update Count     : 1083
    1414//
     15
     16#include "ExpressionNode.h"
    1517
    1618#include <cassert>                 // for assert
     
    2527#include "Common/SemanticError.h"  // for SemanticError
    2628#include "Common/utility.h"        // for maybeMoveBuild, maybeBuild, CodeLo...
    27 #include "ParseNode.h"             // for ExpressionNode, maybeMoveBuildType
     29#include "DeclarationNode.h"       // for DeclarationNode
     30#include "InitializerNode.h"       // for InitializerNode
    2831#include "parserutility.h"         // for notZeroExpr
    2932
     
    699702} // build_binary_val
    700703
    701 ast::Expr * build_binary_ptr( const CodeLocation & location,
    702                 OperKinds op,
    703                 ExpressionNode * expr_node1,
    704                 ExpressionNode * expr_node2 ) {
    705         return build_binary_val( location, op, expr_node1, expr_node2 );
    706 } // build_binary_ptr
    707 
    708704ast::Expr * build_cond( const CodeLocation & location,
    709705                ExpressionNode * expr_node1,
  • src/Parser/InitializerNode.cc

    ra50fdfb r6e1e2d0  
    1414//
    1515
     16#include "InitializerNode.h"
     17
    1618#include <iostream>                // for operator<<, ostream, basic_ostream
    1719#include <list>                    // for list
    1820#include <string>                  // for operator<<, string
    19 
    20 using namespace std;
    2121
    2222#include "AST/Expr.hpp"            // for Expr
     
    2424#include "Common/SemanticError.h"  // for SemanticError
    2525#include "Common/utility.h"        // for maybeBuild
    26 #include "ParseNode.h"             // for InitializerNode, ExpressionNode
     26#include "ExpressionNode.h"        // for ExpressionNode
     27#include "DeclarationNode.h"       // for buildList
     28
     29using namespace std;
    2730
    2831static ast::ConstructFlag toConstructFlag( bool maybeConstructed ) {
  • src/Parser/ParseNode.h

    ra50fdfb r6e1e2d0  
    3838class DeclarationWithType;
    3939class Initializer;
     40class InitializerNode;
    4041class ExpressionNode;
    4142struct StatementNode;
     
    8081}; // ParseNode
    8182
    82 //##############################################################################
    83 
    84 class InitializerNode : public ParseNode {
    85   public:
    86         InitializerNode( ExpressionNode *, bool aggrp = false, ExpressionNode * des = nullptr );
    87         InitializerNode( InitializerNode *, bool aggrp = false, ExpressionNode * des = nullptr );
    88         InitializerNode( bool isDelete );
    89         ~InitializerNode();
    90         virtual InitializerNode * clone() const { assert( false ); return nullptr; }
    91 
    92         ExpressionNode * get_expression() const { return expr; }
    93 
    94         InitializerNode * set_designators( ExpressionNode * des ) { designator = des; return this; }
    95         ExpressionNode * get_designators() const { return designator; }
    96 
    97         InitializerNode * set_maybeConstructed( bool value ) { maybeConstructed = value; return this; }
    98         bool get_maybeConstructed() const { return maybeConstructed; }
    99 
    100         bool get_isDelete() const { return isDelete; }
    101 
    102         InitializerNode * next_init() const { return kids; }
    103 
    104         void print( std::ostream & os, int indent = 0 ) const;
    105         void printOneLine( std::ostream & ) const;
    106 
    107         virtual ast::Init * build() const;
    108   private:
    109         ExpressionNode * expr;
    110         bool aggregate;
    111         ExpressionNode * designator;                                            // may be list
    112         InitializerNode * kids;
    113         bool maybeConstructed;
    114         bool isDelete;
    115 }; // InitializerNode
    116 
    117 //##############################################################################
    118 
    119 class ExpressionNode final : public ParseNode {
    120   public:
    121         ExpressionNode( ast::Expr * expr = nullptr ) : expr( expr ) {}
    122         virtual ~ExpressionNode() {}
    123         virtual ExpressionNode * clone() const override {
    124                 if ( nullptr == expr ) return nullptr;
    125                 return static_cast<ExpressionNode*>(
    126                         (new ExpressionNode( ast::shallowCopy( expr.get() ) ))->set_next( maybeCopy( get_next() ) ));
    127         }
    128 
    129         bool get_extension() const { return extension; }
    130         ExpressionNode * set_extension( bool exten ) { extension = exten; return this; }
    131 
    132         virtual void print( std::ostream & os, __attribute__((unused)) int indent = 0 ) const override {
    133                 os << expr.get();
    134         }
    135         void printOneLine( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const {}
    136 
    137         template<typename T>
    138         bool isExpressionType() const { return nullptr != dynamic_cast<T>(expr.get()); }
    139 
    140         ast::Expr * build() const {
    141                 ast::Expr * node = const_cast<ExpressionNode *>(this)->expr.release();
    142                 node->set_extension( this->get_extension() );
    143                 node->location = this->location;
    144                 return node;
    145         }
    146 
    147         // Public because of lifetime implications (what lifetime implications?)
    148         std::unique_ptr<ast::Expr> expr;
    149   private:
    150         bool extension = false;
    151 }; // ExpressionNode
    152 
    15383// Must harmonize with OperName.
    15484enum class OperKinds {
     
    16999};
    170100
    171 // These 4 routines modify the string:
    172 ast::Expr * build_constantInteger( const CodeLocation &, std::string & );
    173 ast::Expr * build_constantFloat( const CodeLocation &, std::string & );
    174 ast::Expr * build_constantChar( const CodeLocation &, std::string & );
    175 ast::Expr * build_constantStr( const CodeLocation &, std::string & );
    176 ast::Expr * build_field_name_FLOATING_FRACTIONconstant( const CodeLocation &, const std::string & str );
    177 ast::Expr * build_field_name_FLOATING_DECIMALconstant( const CodeLocation &, const std::string & str );
    178 ast::Expr * build_field_name_FLOATINGconstant( const CodeLocation &, const std::string & str );
    179 ast::Expr * build_field_name_fraction_constants( const CodeLocation &, ast::Expr * fieldName, ExpressionNode * fracts );
    180 
    181 ast::NameExpr * build_varref( const CodeLocation &, const std::string * name );
    182 ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation &, const DeclarationNode * decl_node, const ast::NameExpr * name );
    183 ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation &, const ast::EnumDecl * decl, const ast::NameExpr * name );
    184 ast::DimensionExpr * build_dimensionref( const CodeLocation &, const std::string * name );
    185 
    186 ast::Expr * build_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node );
    187 ast::Expr * build_keyword_cast( const CodeLocation &, ast::AggregateDecl::Aggregate target, ExpressionNode * expr_node );
    188 ast::Expr * build_virtual_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node );
    189 ast::Expr * build_fieldSel( const CodeLocation &, ExpressionNode * expr_node, ast::Expr * member );
    190 ast::Expr * build_pfieldSel( const CodeLocation &, ExpressionNode * expr_node, ast::Expr * member );
    191 ast::Expr * build_offsetOf( const CodeLocation &, DeclarationNode * decl_node, ast::NameExpr * member );
    192 ast::Expr * build_and( const CodeLocation &, ExpressionNode * expr_node1, ExpressionNode * expr_node2 );
    193 ast::Expr * build_and_or( const CodeLocation &, ExpressionNode * expr_node1, ExpressionNode * expr_node2, ast::LogicalFlag flag );
    194 ast::Expr * build_unary_val( const CodeLocation &, OperKinds op, ExpressionNode * expr_node );
    195 ast::Expr * build_binary_val( const CodeLocation &, OperKinds op, ExpressionNode * expr_node1, ExpressionNode * expr_node2 );
    196 ast::Expr * build_binary_ptr( const CodeLocation &, OperKinds op, ExpressionNode * expr_node1, ExpressionNode * expr_node2 );
    197 ast::Expr * build_cond( const CodeLocation &, ExpressionNode * expr_node1, ExpressionNode * expr_node2, ExpressionNode * expr_node3 );
    198 ast::Expr * build_tuple( const CodeLocation &, ExpressionNode * expr_node = nullptr );
    199 ast::Expr * build_func( const CodeLocation &, ExpressionNode * function, ExpressionNode * expr_node );
    200 ast::Expr * build_compoundLiteral( const CodeLocation &, DeclarationNode * decl_node, InitializerNode * kids );
    201 
    202 //##############################################################################
    203 
    204 struct TypeData;
    205 
    206 struct DeclarationNode : public ParseNode {
    207         // These enumerations must harmonize with their names in DeclarationNode.cc.
    208         enum BasicType {
    209                 Void, Bool, Char, Int, Int128,
    210                 Float, Double, LongDouble, uuFloat80, uuFloat128,
    211                 uFloat16, uFloat32, uFloat32x, uFloat64, uFloat64x, uFloat128, uFloat128x,
    212                 NoBasicType
    213         };
    214         static const char * basicTypeNames[];
    215         enum ComplexType { Complex, NoComplexType, Imaginary }; // Imaginary unsupported => parse, but make invisible and print error message
    216         static const char * complexTypeNames[];
    217         enum Signedness { Signed, Unsigned, NoSignedness };
    218         static const char * signednessNames[];
    219         enum Length { Short, Long, LongLong, NoLength };
    220         static const char * lengthNames[];
    221         enum BuiltinType { Valist, AutoType, Zero, One, NoBuiltinType };
    222         static const char * builtinTypeNames[];
    223 
    224         static DeclarationNode * newStorageClass( ast::Storage::Classes );
    225         static DeclarationNode * newFuncSpecifier( ast::Function::Specs );
    226         static DeclarationNode * newTypeQualifier( ast::CV::Qualifiers );
    227         static DeclarationNode * newBasicType( BasicType );
    228         static DeclarationNode * newComplexType( ComplexType );
    229         static DeclarationNode * newSignedNess( Signedness );
    230         static DeclarationNode * newLength( Length );
    231         static DeclarationNode * newBuiltinType( BuiltinType );
    232         static DeclarationNode * newForall( DeclarationNode * );
    233         static DeclarationNode * newFromTypedef( const std::string * );
    234         static DeclarationNode * newFromGlobalScope();
    235         static DeclarationNode * newQualifiedType( DeclarationNode *, DeclarationNode * );
    236         static DeclarationNode * newFunction( const std::string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body );
    237         static DeclarationNode * newAggregate( ast::AggregateDecl::Aggregate kind, const std::string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body );
    238         static DeclarationNode * newEnum( const std::string * name, DeclarationNode * constants, bool body, bool typed, DeclarationNode * base = nullptr, EnumHiding hiding = EnumHiding::Visible );
    239         static DeclarationNode * newEnumConstant( const std::string * name, ExpressionNode * constant );
    240         static DeclarationNode * newEnumValueGeneric( const std::string * name, InitializerNode * init );
    241         static DeclarationNode * newEnumInLine( const std::string name );
    242         static DeclarationNode * newName( const std::string * );
    243         static DeclarationNode * newFromTypeGen( const std::string *, ExpressionNode * params );
    244         static DeclarationNode * newTypeParam( ast::TypeDecl::Kind, const std::string * );
    245         static DeclarationNode * newTrait( const std::string * name, DeclarationNode * params, DeclarationNode * asserts );
    246         static DeclarationNode * newTraitUse( const std::string * name, ExpressionNode * params );
    247         static DeclarationNode * newTypeDecl( const std::string * name, DeclarationNode * typeParams );
    248         static DeclarationNode * newPointer( DeclarationNode * qualifiers, OperKinds kind );
    249         static DeclarationNode * newArray( ExpressionNode * size, DeclarationNode * qualifiers, bool isStatic );
    250         static DeclarationNode * newVarArray( DeclarationNode * qualifiers );
    251         static DeclarationNode * newBitfield( ExpressionNode * size );
    252         static DeclarationNode * newTuple( DeclarationNode * members );
    253         static DeclarationNode * newTypeof( ExpressionNode * expr, bool basetypeof = false );
    254         static DeclarationNode * newVtableType( DeclarationNode * expr );
    255         static DeclarationNode * newAttribute( const std::string *, ExpressionNode * expr = nullptr ); // gcc attributes
    256         static DeclarationNode * newDirectiveStmt( StatementNode * stmt ); // gcc external directive statement
    257         static DeclarationNode * newAsmStmt( StatementNode * stmt ); // gcc external asm statement
    258         static DeclarationNode * newStaticAssert( ExpressionNode * condition, ast::Expr * message );
    259 
    260         DeclarationNode();
    261         ~DeclarationNode();
    262         DeclarationNode * clone() const override;
    263 
    264         DeclarationNode * addQualifiers( DeclarationNode * );
    265         void checkQualifiers( const TypeData *, const TypeData * );
    266         void checkSpecifiers( DeclarationNode * );
    267         DeclarationNode * copySpecifiers( DeclarationNode * );
    268         DeclarationNode * addType( DeclarationNode * );
    269         DeclarationNode * addTypedef();
    270         DeclarationNode * addEnumBase( DeclarationNode * );
    271         DeclarationNode * addAssertions( DeclarationNode * );
    272         DeclarationNode * addName( std::string * );
    273         DeclarationNode * addAsmName( DeclarationNode * );
    274         DeclarationNode * addBitfield( ExpressionNode * size );
    275         DeclarationNode * addVarArgs();
    276         DeclarationNode * addFunctionBody( StatementNode * body, ExpressionNode * with = nullptr );
    277         DeclarationNode * addOldDeclList( DeclarationNode * list );
    278         DeclarationNode * setBase( TypeData * newType );
    279         DeclarationNode * copyAttribute( DeclarationNode * attr );
    280         DeclarationNode * addPointer( DeclarationNode * qualifiers );
    281         DeclarationNode * addArray( DeclarationNode * array );
    282         DeclarationNode * addNewPointer( DeclarationNode * pointer );
    283         DeclarationNode * addNewArray( DeclarationNode * array );
    284         DeclarationNode * addParamList( DeclarationNode * list );
    285         DeclarationNode * addIdList( DeclarationNode * list ); // old-style functions
    286         DeclarationNode * addInitializer( InitializerNode * init );
    287         DeclarationNode * addTypeInitializer( DeclarationNode * init );
    288 
    289         DeclarationNode * cloneType( std::string * newName );
    290         DeclarationNode * cloneBaseType( DeclarationNode * newdecl );
    291 
    292         DeclarationNode * appendList( DeclarationNode * node ) {
    293                 return (DeclarationNode *)set_last( node );
    294         }
    295 
    296         virtual void print( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const override;
    297         virtual void printList( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const override;
    298 
    299         ast::Decl * build() const;
    300         ast::Type * buildType() const;
    301 
    302         ast::Linkage::Spec get_linkage() const { return linkage; }
    303         DeclarationNode * extractAggregate() const;
    304         bool has_enumeratorValue() const { return (bool)enumeratorValue; }
    305         ExpressionNode * consume_enumeratorValue() const { return const_cast<DeclarationNode *>(this)->enumeratorValue.release(); }
    306 
    307         bool get_extension() const { return extension; }
    308         DeclarationNode * set_extension( bool exten ) { extension = exten; return this; }
    309 
    310         bool get_inLine() const { return inLine; }
    311         DeclarationNode * set_inLine( bool inL ) { inLine = inL; return this; }
    312 
    313         DeclarationNode * get_last() { return (DeclarationNode *)ParseNode::get_last(); }
    314 
    315         struct Variable_t {
    316 //              const std::string * name;
    317                 ast::TypeDecl::Kind tyClass;
    318                 DeclarationNode * assertions;
    319                 DeclarationNode * initializer;
    320         };
    321         Variable_t variable;
    322 
    323         struct StaticAssert_t {
    324                 ExpressionNode * condition;
    325                 ast::Expr * message;
    326         };
    327         StaticAssert_t assert;
    328 
    329         BuiltinType builtin = NoBuiltinType;
    330 
    331         TypeData * type = nullptr;
    332 
    333         bool inLine = false;
    334         bool enumInLine = false;
    335         ast::Function::Specs funcSpecs;
    336         ast::Storage::Classes storageClasses;
    337 
    338         ExpressionNode * bitfieldWidth = nullptr;
    339         std::unique_ptr<ExpressionNode> enumeratorValue;
    340         bool hasEllipsis = false;
    341         ast::Linkage::Spec linkage;
    342         ast::Expr * asmName = nullptr;
    343         std::vector<ast::ptr<ast::Attribute>> attributes;
    344         InitializerNode * initializer = nullptr;
    345         bool extension = false;
    346         std::string error;
    347         StatementNode * asmStmt = nullptr;
    348         StatementNode * directiveStmt = nullptr;
    349 
    350         static UniqueName anonymous;
    351 }; // DeclarationNode
    352 
    353 ast::Type * buildType( TypeData * type );
    354 
    355 static inline ast::Type * maybeMoveBuildType( const DeclarationNode * orig ) {
    356         ast::Type * ret = orig ? orig->buildType() : nullptr;
    357         delete orig;
    358         return ret;
    359 }
    360 
    361 //##############################################################################
    362 
    363 struct StatementNode final : public ParseNode {
    364         StatementNode() :
    365                 stmt( nullptr ), clause( nullptr ) {}
    366         StatementNode( ast::Stmt * stmt ) :
    367                 stmt( stmt ), clause( nullptr ) {}
    368         StatementNode( ast::StmtClause * clause ) :
    369                 stmt( nullptr ), clause( clause ) {}
    370         StatementNode( DeclarationNode * decl );
    371         virtual ~StatementNode() {}
    372 
    373         virtual StatementNode * clone() const final { assert( false ); return nullptr; }
    374         ast::Stmt * build() const { return const_cast<StatementNode *>(this)->stmt.release(); }
    375 
    376         virtual StatementNode * add_label(
    377                         const CodeLocation & location,
    378                         const std::string * name,
    379                         DeclarationNode * attr = nullptr ) {
    380                 stmt->labels.emplace_back( location,
    381                         *name,
    382                         attr ? std::move( attr->attributes )
    383                                 : std::vector<ast::ptr<ast::Attribute>>{} );
    384                 delete attr;
    385                 delete name;
    386                 return this;
    387         }
    388 
    389         virtual StatementNode * append_last_case( StatementNode * );
    390 
    391         virtual void print( std::ostream & os, __attribute__((unused)) int indent = 0 ) const override {
    392                 os << stmt.get() << std::endl;
    393         }
    394 
    395         std::unique_ptr<ast::Stmt> stmt;
    396         std::unique_ptr<ast::StmtClause> clause;
    397 }; // StatementNode
    398 
    399 ast::Stmt * build_expr( CodeLocation const &, ExpressionNode * ctl );
    400 
    401 struct CondCtl {
    402         CondCtl( DeclarationNode * decl, ExpressionNode * condition ) :
    403                 init( decl ? new StatementNode( decl ) : nullptr ), condition( condition ) {}
    404 
    405         StatementNode * init;
    406         ExpressionNode * condition;
    407 };
    408 
    409 struct ForCtrl {
    410         ForCtrl( StatementNode * stmt, ExpressionNode * condition, ExpressionNode * change ) :
    411                 init( stmt ), condition( condition ), change( change ) {}
    412 
    413         StatementNode * init;
    414         ExpressionNode * condition;
    415         ExpressionNode * change;
    416 };
    417 
    418 ast::Stmt * build_if( const CodeLocation &, CondCtl * ctl, StatementNode * then, StatementNode * else_ );
    419 ast::Stmt * build_switch( const CodeLocation &, bool isSwitch, ExpressionNode * ctl, StatementNode * stmt );
    420 ast::CaseClause * build_case( ExpressionNode * ctl );
    421 ast::CaseClause * build_default( const CodeLocation & );
    422 ast::Stmt * build_while( const CodeLocation &, CondCtl * ctl, StatementNode * stmt, StatementNode * else_ = nullptr );
    423 ast::Stmt * build_do_while( const CodeLocation &, ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ = nullptr );
    424 ast::Stmt * build_for( const CodeLocation &, ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ = nullptr );
    425 ast::Stmt * build_branch( const CodeLocation &, ast::BranchStmt::Kind kind );
    426 ast::Stmt * build_branch( const CodeLocation &, std::string * identifier, ast::BranchStmt::Kind kind );
    427 ast::Stmt * build_computedgoto( ExpressionNode * ctl );
    428 ast::Stmt * build_return( const CodeLocation &, ExpressionNode * ctl );
    429 ast::Stmt * build_throw( const CodeLocation &, ExpressionNode * ctl );
    430 ast::Stmt * build_resume( const CodeLocation &, ExpressionNode * ctl );
    431 ast::Stmt * build_resume_at( ExpressionNode * ctl , ExpressionNode * target );
    432 ast::Stmt * build_try( const CodeLocation &, StatementNode * try_, StatementNode * catch_, StatementNode * finally_ );
    433 ast::CatchClause * build_catch( const CodeLocation &, ast::ExceptionKind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body );
    434 ast::FinallyClause * build_finally( const CodeLocation &, StatementNode * stmt );
    435 ast::Stmt * build_compound( const CodeLocation &, StatementNode * first );
    436 StatementNode * maybe_build_compound( const CodeLocation &, StatementNode * first );
    437 ast::Stmt * build_asm( const CodeLocation &, bool voltile, ast::Expr * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr );
    438 ast::Stmt * build_directive( const CodeLocation &, std::string * directive );
    439 ast::SuspendStmt * build_suspend( const CodeLocation &, StatementNode *, ast::SuspendStmt::Type );
    440 ast::WaitForStmt * build_waitfor( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt );
    441 ast::WaitForStmt * build_waitfor_else( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt );
    442 ast::WaitForStmt * build_waitfor_timeout( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt );
    443 ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation &, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt );
    444 ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation &, ExpressionNode * when, StatementNode * stmt );
    445 ast::WaitUntilStmt::ClauseNode * build_waituntil_timeout( const CodeLocation &, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt );
    446 ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation &, ast::WaitUntilStmt::ClauseNode * root );
    447 ast::Stmt * build_with( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );
    448 ast::Stmt * build_mutex( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );
    449 
    450 //##############################################################################
    451 
    452 template<typename AstType, typename NodeType,
    453         template<typename, typename...> class Container, typename... Args>
    454 void buildList( const NodeType * firstNode,
    455                 Container<ast::ptr<AstType>, Args...> & output ) {
    456         SemanticErrorException errors;
    457         std::back_insert_iterator<Container<ast::ptr<AstType>, Args...>> out( output );
    458         const NodeType * cur = firstNode;
    459 
    460         while ( cur ) {
    461                 try {
    462                         if ( auto result = dynamic_cast<AstType *>( maybeBuild( cur ) ) ) {
    463                                 *out++ = result;
    464                         } else {
    465                                 assertf(false, __PRETTY_FUNCTION__ );
    466                                 SemanticError( cur->location, "type specifier declaration in forall clause is currently unimplemented." );
    467                         } // if
    468                 } catch( SemanticErrorException & e ) {
    469                         errors.append( e );
    470                 } // try
    471                 const ParseNode * temp = cur->get_next();
    472                 // Should not return nullptr, then it is non-homogeneous:
    473                 cur = dynamic_cast<const NodeType *>( temp );
    474                 if ( !cur && temp ) {
    475                         SemanticError( temp->location, "internal error, non-homogeneous nodes founds in buildList processing." );
    476                 } // if
    477         } // while
    478         if ( ! errors.isEmpty() ) {
    479                 throw errors;
    480         } // if
    481 }
    482 
    483 // in DeclarationNode.cc
    484 void buildList( const DeclarationNode * firstNode, std::vector<ast::ptr<ast::Decl>> & outputList );
    485 void buildList( const DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList );
    486 void buildTypeList( const DeclarationNode * firstNode, std::vector<ast::ptr<ast::Type>> & outputList );
    487 
    488 template<typename AstType, typename NodeType,
    489         template<typename, typename...> class Container, typename... Args>
    490 void buildMoveList( const NodeType * firstNode,
    491                 Container<ast::ptr<AstType>, Args...> & output ) {
    492         buildList<AstType, NodeType, Container, Args...>( firstNode, output );
    493         delete firstNode;
    494 }
    495 
    496 // in ParseNode.cc
    497101std::ostream & operator<<( std::ostream & out, const ParseNode * node );
    498102
  • src/Parser/RunParser.cpp

    ra50fdfb r6e1e2d0  
    2020#include "CodeTools/TrackLoc.h"             // for fillLocations
    2121#include "Common/CodeLocationTools.hpp"     // for forceFillCodeLocations
    22 #include "Parser/ParseNode.h"               // for DeclarationNode, buildList
     22#include "Parser/DeclarationNode.h"         // for DeclarationNode, buildList
    2323#include "Parser/TypedefTable.h"            // for TypedefTable
    2424
  • src/Parser/StatementNode.cc

    ra50fdfb r6e1e2d0  
    1111// Created On       : Sat May 16 14:59:41 2015
    1212// Last Modified By : Andrew Beach
    13 // Last Modified On : Tue Apr  4 11:40:00 2023
    14 // Update Count     : 427
     13// Last Modified On : Tue Apr 11 10:16:00 2023
     14// Update Count     : 428
    1515//
     16
     17#include "StatementNode.h"
    1618
    1719#include <cassert>                 // for assert, strict_dynamic_cast, assertf
     
    2325#include "Common/SemanticError.h"  // for SemanticError
    2426#include "Common/utility.h"        // for maybeMoveBuild, maybeBuild
    25 #include "ParseNode.h"             // for StatementNode, ExpressionNode, bui...
     27#include "DeclarationNode.h"       // for DeclarationNode
     28#include "ExpressionNode.h"        // for ExpressionNode
    2629#include "parserutility.h"         // for notZeroExpr
    2730
     
    2932
    3033using namespace std;
     34
     35// Some helpers for cases that really want a single node but check for lists.
     36static const ast::Stmt * buildMoveSingle( StatementNode * node ) {
     37        std::vector<ast::ptr<ast::Stmt>> list;
     38        buildMoveList( node, list );
     39        assertf( list.size() == 1, "CFA Internal Error: Extra/Missing Nodes" );
     40        return list.front().release();
     41}
     42
     43static const ast::Stmt * buildMoveOptional( StatementNode * node ) {
     44        std::vector<ast::ptr<ast::Stmt>> list;
     45        buildMoveList( node, list );
     46        assertf( list.size() <= 1, "CFA Internal Error: Extra Nodes" );
     47        return list.empty() ? nullptr : list.front().release();
     48}
    3149
    3250StatementNode::StatementNode( DeclarationNode * decl ) {
     
    5371} // StatementNode::StatementNode
    5472
    55 StatementNode * StatementNode::append_last_case( StatementNode * stmt ) {
    56         StatementNode * prev = this;
     73StatementNode * StatementNode::add_label(
     74                const CodeLocation & location,
     75                const std::string * name,
     76                DeclarationNode * attr ) {
     77        stmt->labels.emplace_back( location,
     78                *name,
     79                attr ? std::move( attr->attributes )
     80                        : std::vector<ast::ptr<ast::Attribute>>{} );
     81        delete attr;
     82        delete name;
     83        return this;
     84}
     85
     86ClauseNode * ClauseNode::append_last_case( StatementNode * stmt ) {
     87        ClauseNode * prev = this;
    5788        // find end of list and maintain previous pointer
    58         for ( StatementNode * curr = prev; curr != nullptr; curr = (StatementNode *)curr->get_next() ) {
    59                 StatementNode * node = strict_dynamic_cast< StatementNode * >(curr);
    60                 assert( nullptr == node->stmt.get() );
     89        for ( ClauseNode * curr = prev; curr != nullptr; curr = (ClauseNode *)curr->get_next() ) {
     90                ClauseNode * node = strict_dynamic_cast< ClauseNode * >(curr);
    6191                assert( dynamic_cast<ast::CaseClause *>( node->clause.get() ) );
    6292                prev = curr;
    6393        } // for
     94        ClauseNode * node = dynamic_cast< ClauseNode * >(prev);
    6495        // convert from StatementNode list to Statement list
    65         StatementNode * node = dynamic_cast< StatementNode * >(prev);
    6696        std::vector<ast::ptr<ast::Stmt>> stmts;
    6797        buildMoveList( stmt, stmts );
     
    73103        stmts.clear();
    74104        return this;
    75 } // StatementNode::append_last_case
     105} // ClauseNode::append_last_case
    76106
    77107ast::Stmt * build_expr( CodeLocation const & location, ExpressionNode * ctl ) {
     
    97127                for ( ast::ptr<ast::Stmt> & stmt : inits ) {
    98128                        // build the && of all of the declared variables compared against 0
    99                         //auto declStmt = strict_dynamic_cast<ast::DeclStmt *>( stmt );
    100129                        auto declStmt = stmt.strict_as<ast::DeclStmt>();
    101                         //ast::DeclWithType * dwt = strict_dynamic_cast<ast::DeclWithType *>( declStmt->decl );
    102130                        auto dwt = declStmt->decl.strict_as<ast::DeclWithType>();
    103131                        ast::Expr * nze = notZeroExpr( new ast::VariableExpr( dwt->location, dwt ) );
     
    113141        ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
    114142
    115         std::vector<ast::ptr<ast::Stmt>> aststmt;
    116         buildMoveList( then, aststmt );
    117         assert( aststmt.size() == 1 );
    118         ast::Stmt const * astthen = aststmt.front().release();
    119 
    120         ast::Stmt const * astelse = nullptr;
    121         if ( else_ ) {
    122                 std::vector<ast::ptr<ast::Stmt>> aststmt;
    123                 buildMoveList( else_, aststmt );
    124                 assert( aststmt.size() == 1 );
    125                 astelse = aststmt.front().release();
    126         } // if
     143        ast::Stmt const * astthen = buildMoveSingle( then );
     144        ast::Stmt const * astelse = buildMoveOptional( else_ );
    127145
    128146        return new ast::IfStmt( location, astcond, astthen, astelse,
     
    131149} // build_if
    132150
    133 // Temporary work around. Split StmtClause off from StatementNode.
    134 template<typename clause_t>
    135 static void buildMoveClauseList( StatementNode * firstNode,
    136                 std::vector<ast::ptr<clause_t>> & output ) {
    137         SemanticErrorException errors;
    138         std::back_insert_iterator<std::vector<ast::ptr<clause_t>>>
    139                 out( output );
    140         StatementNode * cur = firstNode;
    141 
    142         while ( cur ) {
    143                 try {
    144                         auto clause = cur->clause.release();
    145                         if ( auto result = dynamic_cast<clause_t *>( clause ) ) {
    146                                 *out++ = result;
    147                         } else {
    148                                 assertf(false, __PRETTY_FUNCTION__ );
    149                                 SemanticError( cur->location, "type specifier declaration in forall clause is currently unimplemented." );
    150                         } // if
    151                 } catch( SemanticErrorException & e ) {
    152                         errors.append( e );
    153                 } // try
    154                 ParseNode * temp = cur->get_next();
    155                 // Should not return nullptr, then it is non-homogeneous:
    156                 cur = dynamic_cast<StatementNode *>( temp );
    157                 if ( !cur && temp ) {
    158                         SemanticError( temp->location, "internal error, non-homogeneous nodes founds in buildList processing." );
    159                 } // if
    160         } // while
    161         if ( ! errors.isEmpty() ) {
    162                 throw errors;
    163         } // if
    164         // Usually in the wrapper.
    165         delete firstNode;
    166 }
    167 
    168 ast::Stmt * build_switch( const CodeLocation & location, bool isSwitch, ExpressionNode * ctl, StatementNode * stmt ) {
     151ast::Stmt * build_switch( const CodeLocation & location, bool isSwitch, ExpressionNode * ctl, ClauseNode * stmt ) {
    169152        std::vector<ast::ptr<ast::CaseClause>> aststmt;
    170         buildMoveClauseList( stmt, aststmt );
     153        buildMoveList( stmt, aststmt );
    171154        // If it is not a switch it is a choose statement.
    172155        if ( ! isSwitch ) {
     
    190173} // build_switch
    191174
    192 ast::CaseClause * build_case( ExpressionNode * ctl ) {
     175ast::CaseClause * build_case( const CodeLocation & location, ExpressionNode * ctl ) {
    193176        // stmt starts empty and then added to
    194177        auto expr = maybeMoveBuild( ctl );
    195         return new ast::CaseClause( expr->location, expr, {} );
     178        return new ast::CaseClause( location, expr, {} );
    196179} // build_case
    197180
     
    205188        ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
    206189
    207         std::vector<ast::ptr<ast::Stmt>> aststmt;                                               // loop body, compound created if empty
    208         buildMoveList( stmt, aststmt );
    209         assert( aststmt.size() == 1 );
    210 
    211         std::vector<ast::ptr<ast::Stmt>> astelse;                                               // else clause, maybe empty
    212         buildMoveList( else_, astelse );
    213         assert( astelse.size() <= 1 );
    214 
    215190        return new ast::WhileDoStmt( location,
    216191                astcond,
    217                 aststmt.front(),
    218                 astelse.empty() ? nullptr : astelse.front().release(),
     192                buildMoveSingle( stmt ),
     193                buildMoveOptional( else_ ),
    219194                std::move( astinit ),
    220                 false
     195                ast::While
    221196        );
    222197} // build_while
    223198
    224199ast::Stmt * build_do_while( const CodeLocation & location, ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ ) {
    225         std::vector<ast::ptr<ast::Stmt>> aststmt;                                               // loop body, compound created if empty
    226         buildMoveList( stmt, aststmt );
    227         assert( aststmt.size() == 1 );                                          // compound created if empty
    228 
    229         std::vector<ast::ptr<ast::Stmt>> astelse;                                               // else clause, maybe empty
    230         buildMoveList( else_, astelse );
    231         assert( astelse.size() <= 1 );
    232 
    233200        // do-while cannot have declarations in the contitional, so init is always empty
    234201        return new ast::WhileDoStmt( location,
    235202                notZeroExpr( maybeMoveBuild( ctl ) ),
    236                 aststmt.front(),
    237                 astelse.empty() ? nullptr : astelse.front().release(),
     203                buildMoveSingle( stmt ),
     204                buildMoveOptional( else_ ),
    238205                {},
    239                 true
     206                ast::DoWhile
    240207        );
    241208} // build_do_while
     
    251218        astincr = maybeMoveBuild( forctl->change );
    252219        delete forctl;
    253 
    254         std::vector<ast::ptr<ast::Stmt>> aststmt;                                               // loop body, compound created if empty
    255         buildMoveList( stmt, aststmt );
    256         assert( aststmt.size() == 1 );
    257 
    258         std::vector<ast::ptr<ast::Stmt>> astelse;                                               // else clause, maybe empty
    259         buildMoveList( else_, astelse );
    260         assert( astelse.size() <= 1 );
    261220
    262221        return new ast::ForStmt( location,
     
    264223                astcond,
    265224                astincr,
    266                 aststmt.front(),
    267                 astelse.empty() ? nullptr : astelse.front().release()
     225                buildMoveSingle( stmt ),
     226                buildMoveOptional( else_ )
    268227        );
    269228} // build_for
     
    326285} // build_resume_at
    327286
    328 ast::Stmt * build_try( const CodeLocation & location, StatementNode * try_, StatementNode * catch_, StatementNode * finally_ ) {
     287ast::Stmt * build_try( const CodeLocation & location, StatementNode * try_, ClauseNode * catch_, ClauseNode * finally_ ) {
    329288        std::vector<ast::ptr<ast::CatchClause>> aststmt;
    330         buildMoveClauseList( catch_, aststmt );
     289        buildMoveList( catch_, aststmt );
    331290        ast::CompoundStmt * tryBlock = strict_dynamic_cast<ast::CompoundStmt *>( maybeMoveBuild( try_ ) );
    332291        ast::FinallyClause * finallyBlock = nullptr;
     
    342301
    343302ast::CatchClause * build_catch( const CodeLocation & location, ast::ExceptionKind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body ) {
    344         std::vector<ast::ptr<ast::Stmt>> aststmt;
    345         buildMoveList( body, aststmt );
    346         assert( aststmt.size() == 1 );
    347303        return new ast::CatchClause( location,
    348304                kind,
    349305                maybeMoveBuild( decl ),
    350306                maybeMoveBuild( cond ),
    351                 aststmt.front().release()
     307                buildMoveSingle( body )
    352308        );
    353309} // build_catch
    354310
    355311ast::FinallyClause * build_finally( const CodeLocation & location, StatementNode * stmt ) {
    356         std::vector<ast::ptr<ast::Stmt>> aststmt;
    357         buildMoveList( stmt, aststmt );
    358         assert( aststmt.size() == 1 );
    359312        return new ast::FinallyClause( location,
    360                 aststmt.front().strict_as<ast::CompoundStmt>()
     313                strict_dynamic_cast<const ast::CompoundStmt *>(
     314                        buildMoveSingle( stmt )
     315                )
    361316        );
    362317} // build_finally
    363318
    364 ast::SuspendStmt * build_suspend( const CodeLocation & location, StatementNode * then, ast::SuspendStmt::Type type ) {
    365         std::vector<ast::ptr<ast::Stmt>> stmts;
    366         buildMoveList( then, stmts );
    367         ast::CompoundStmt const * then2 = nullptr;
    368         if(!stmts.empty()) {
    369                 assert( stmts.size() == 1 );
    370                 then2 = stmts.front().strict_as<ast::CompoundStmt>();
    371         }
    372         auto node = new ast::SuspendStmt( location, then2, ast::SuspendStmt::None );
    373         node->type = type;
    374         return node;
     319ast::SuspendStmt * build_suspend( const CodeLocation & location, StatementNode * then, ast::SuspendStmt::Kind kind ) {
     320        return new ast::SuspendStmt( location,
     321                strict_dynamic_cast<const ast::CompoundStmt *, nullptr>(
     322                        buildMoveOptional( then )
     323                ),
     324                kind
     325        );
    375326} // build_suspend
    376327
     
    525476
    526477// Question
    527 ast::Stmt * build_asm( const CodeLocation & location, bool voltile, ast::Expr * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
     478ast::Stmt * build_asm( const CodeLocation & location, bool is_volatile, ExpressionNode * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
    528479        std::vector<ast::ptr<ast::Expr>> out, in;
    529480        std::vector<ast::ptr<ast::ConstantExpr>> clob;
     
    533484        buildMoveList( clobber, clob );
    534485        return new ast::AsmStmt( location,
    535                 voltile,
    536                 instruction,
     486                is_volatile,
     487                maybeMoveBuild( instruction ),
    537488                std::move( out ),
    538489                std::move( in ),
  • src/Parser/TypeData.cc

    ra50fdfb r6e1e2d0  
    2424#include "Common/SemanticError.h"  // for SemanticError
    2525#include "Common/utility.h"        // for splice, spliceBegin
    26 #include "Parser/parserutility.h"  // for maybeCopy, maybeBuild, maybeMoveB...
    27 #include "Parser/ParseNode.h"      // for DeclarationNode, ExpressionNode
     26#include "Parser/ExpressionNode.h" // for ExpressionNode
     27#include "Parser/StatementNode.h"  // for StatementNode
    2828
    2929class Attribute;
     
    13971397                std::move( attributes ),
    13981398                funcSpec,
    1399                 isVarArgs
     1399                (isVarArgs) ? ast::VariableArgs : ast::FixedArgs
    14001400        );
    14011401        buildList( td->function.withExprs, decl->withExprs );
  • src/Parser/TypeData.h

    ra50fdfb r6e1e2d0  
    1616#pragma once
    1717
    18 #include <iosfwd>                                                                               // for ostream
    19 #include <list>                                                                                 // for list
    20 #include <string>                                                                               // for string
     18#include <iosfwd>                                   // for ostream
     19#include <list>                                     // for list
     20#include <string>                                   // for string
    2121
    22 #include "AST/Type.hpp"                                                                 // for Type
    23 #include "ParseNode.h"                                                                  // for DeclarationNode, DeclarationNode::Ag...
     22#include "AST/Type.hpp"                             // for Type
     23#include "DeclarationNode.h"                        // for DeclarationNode
    2424
    2525struct TypeData {
  • src/Parser/TypedefTable.cc

    ra50fdfb r6e1e2d0  
    1616
    1717#include "TypedefTable.h"
    18 #include <cassert>                                                                              // for assert
    19 #include <iostream>
     18
     19#include <cassert>                                // for assert
     20#include <string>                                 // for string
     21#include <iostream>                               // for iostream
     22
     23#include "ExpressionNode.h"                       // for LabelNode
     24#include "ParserTypes.h"                          // for Token
     25#include "StatementNode.h"                        // for CondCtl, ForCtrl
     26// This (generated) header must come late as it is missing includes.
     27#include "parser.hh"              // for IDENTIFIER, TYPEDEFname, TYPEGENname
     28
    2029using namespace std;
    2130
    2231#if 0
    2332#define debugPrint( code ) code
     33
     34static const char *kindName( int kind ) {
     35        switch ( kind ) {
     36        case IDENTIFIER: return "identifier";
     37        case TYPEDIMname: return "typedim";
     38        case TYPEDEFname: return "typedef";
     39        case TYPEGENname: return "typegen";
     40        default:
     41                cerr << "Error: cfa-cpp internal error, invalid kind of identifier" << endl;
     42                abort();
     43        } // switch
     44} // kindName
    2445#else
    2546#define debugPrint( code )
    2647#endif
    27 
    28 using namespace std;                                                                    // string, iostream
    29 
    30 debugPrint(
    31         static const char *kindName( int kind ) {
    32                 switch ( kind ) {
    33                 case IDENTIFIER: return "identifier";
    34                 case TYPEDIMname: return "typedim";
    35                 case TYPEDEFname: return "typedef";
    36                 case TYPEGENname: return "typegen";
    37                 default:
    38                         cerr << "Error: cfa-cpp internal error, invalid kind of identifier" << endl;
    39                         abort();
    40                 } // switch
    41         } // kindName
    42 );
    4348
    4449TypedefTable::~TypedefTable() {
     
    7883                typedefTable.addToEnclosingScope( name, kind, "MTD" );
    7984        } // if
     85} // TypedefTable::makeTypedef
     86
     87void TypedefTable::makeTypedef( const string & name ) {
     88        return makeTypedef( name, TYPEDEFname );
    8089} // TypedefTable::makeTypedef
    8190
  • src/Parser/TypedefTable.h

    ra50fdfb r6e1e2d0  
    1919
    2020#include "Common/ScopedMap.h"                                                   // for ScopedMap
    21 #include "ParserTypes.h"
    22 #include "parser.hh"                                                                    // for IDENTIFIER, TYPEDEFname, TYPEGENname
    2321
    2422class TypedefTable {
    2523        struct Note { size_t level; bool forall; };
    2624        typedef ScopedMap< std::string, int, Note > KindTable;
    27         KindTable kindTable;   
     25        KindTable kindTable;
    2826        unsigned int level = 0;
    2927  public:
     
    3331        bool existsCurr( const std::string & identifier ) const;
    3432        int isKind( const std::string & identifier ) const;
    35         void makeTypedef( const std::string & name, int kind = TYPEDEFname );
     33        void makeTypedef( const std::string & name, int kind );
     34        void makeTypedef( const std::string & name );
    3635        void addToScope( const std::string & identifier, int kind, const char * );
    3736        void addToEnclosingScope( const std::string & identifier, int kind, const char * );
  • src/Parser/lex.ll

    ra50fdfb r6e1e2d0  
    4444
    4545#include "config.h"                                                                             // configure info
     46#include "DeclarationNode.h"                            // for DeclarationNode
     47#include "ExpressionNode.h"                             // for LabelNode
     48#include "InitializerNode.h"                            // for InitializerNode
    4649#include "ParseNode.h"
     50#include "ParserTypes.h"                                // for Token
     51#include "StatementNode.h"                              // for CondCtl, ForCtrl
    4752#include "TypedefTable.h"
     53// This (generated) header must come late as it is missing includes.
     54#include "parser.hh"                                    // generated info
    4855
    4956string * build_postfix_name( string * name );
  • src/Parser/module.mk

    ra50fdfb r6e1e2d0  
    2121SRC += \
    2222       Parser/DeclarationNode.cc \
     23       Parser/DeclarationNode.h \
    2324       Parser/ExpressionNode.cc \
     25       Parser/ExpressionNode.h \
    2426       Parser/InitializerNode.cc \
     27       Parser/InitializerNode.h \
    2528       Parser/lex.ll \
    2629       Parser/ParseNode.cc \
     
    3336       Parser/RunParser.hpp \
    3437       Parser/StatementNode.cc \
     38       Parser/StatementNode.h \
    3539       Parser/TypeData.cc \
    3640       Parser/TypeData.h \
  • src/Parser/parser.yy

    ra50fdfb r6e1e2d0  
    99// Author           : Peter A. Buhr
    1010// Created On       : Sat Sep  1 20:22:55 2001
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Apr  4 14:02:00 2023
    13 // Update Count     : 6329
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Wed Apr 26 16:45:37 2023
     13// Update Count     : 6330
    1414//
    1515
     
    4848using namespace std;
    4949
    50 #include "SynTree/Declaration.h"
    51 #include "ParseNode.h"
     50#include "SynTree/Type.h"                               // for Type
     51#include "DeclarationNode.h"                            // for DeclarationNode, ...
     52#include "ExpressionNode.h"                             // for ExpressionNode, ...
     53#include "InitializerNode.h"                            // for InitializerNode, ...
     54#include "ParserTypes.h"
     55#include "StatementNode.h"                              // for build_...
    5256#include "TypedefTable.h"
    5357#include "TypeData.h"
    54 #include "SynTree/LinkageSpec.h"
    5558#include "Common/SemanticError.h"                                               // error_str
    5659#include "Common/utility.h"                                                             // for maybeMoveBuild, maybeBuild, CodeLo...
     
    297300%union {
    298301        Token tok;
    299         ParseNode * pn;
    300         ExpressionNode * en;
     302        ExpressionNode * expr;
    301303        DeclarationNode * decl;
    302304        ast::AggregateDecl::Aggregate aggKey;
    303305        ast::TypeDecl::Kind tclass;
    304         StatementNode * sn;
     306        StatementNode * stmt;
     307        ClauseNode * clause;
    305308        ast::WaitForStmt * wfs;
    306     ast::WaitUntilStmt::ClauseNode * wuscn;
    307         ast::Expr * constant;
     309    ast::WaitUntilStmt::ClauseNode * wucn;
    308310        CondCtl * ifctl;
    309         ForCtrl * fctl;
    310         OperKinds compop;
    311         LabelNode * label;
    312         InitializerNode * in;
    313         OperKinds op;
     311        ForCtrl * forctl;
     312        LabelNode * labels;
     313        InitializerNode * init;
     314        OperKinds oper;
    314315        std::string * str;
    315         bool flag;
    316         EnumHiding hide;
    317         ast::ExceptionKind catch_kind;
     316        bool is_volatile;
     317        EnumHiding enum_hiding;
     318        ast::ExceptionKind except_kind;
    318319        ast::GenericExpr * genexpr;
    319320}
     
    381382%type<tok> identifier                                   identifier_at                           identifier_or_type_name         attr_name
    382383%type<tok> quasi_keyword
    383 %type<constant> string_literal
     384%type<expr> string_literal
    384385%type<str> string_literal_list
    385386
    386 %type<hide> hide_opt                                    visible_hide_opt
     387%type<enum_hiding> hide_opt                                     visible_hide_opt
    387388
    388389// expressions
    389 %type<en> constant
    390 %type<en> tuple                                                 tuple_expression_list
    391 %type<op> ptrref_operator                               unary_operator                          assignment_operator                     simple_assignment_operator      compound_assignment_operator
    392 %type<en> primary_expression                    postfix_expression                      unary_expression
    393 %type<en> cast_expression_list                  cast_expression                         exponential_expression          multiplicative_expression       additive_expression
    394 %type<en> shift_expression                              relational_expression           equality_expression
    395 %type<en> AND_expression                                exclusive_OR_expression         inclusive_OR_expression
    396 %type<en> logical_AND_expression                logical_OR_expression
    397 %type<en> conditional_expression                constant_expression                     assignment_expression           assignment_expression_opt
    398 %type<en> comma_expression                              comma_expression_opt
    399 %type<en> argument_expression_list_opt  argument_expression_list        argument_expression                     default_initializer_opt
     390%type<expr> constant
     391%type<expr> tuple                                                       tuple_expression_list
     392%type<oper> ptrref_operator                             unary_operator                          assignment_operator                     simple_assignment_operator      compound_assignment_operator
     393%type<expr> primary_expression                  postfix_expression                      unary_expression
     394%type<expr> cast_expression_list                        cast_expression                         exponential_expression          multiplicative_expression       additive_expression
     395%type<expr> shift_expression                            relational_expression           equality_expression
     396%type<expr> AND_expression                              exclusive_OR_expression         inclusive_OR_expression
     397%type<expr> logical_AND_expression              logical_OR_expression
     398%type<expr> conditional_expression              constant_expression                     assignment_expression           assignment_expression_opt
     399%type<expr> comma_expression                            comma_expression_opt
     400%type<expr> argument_expression_list_opt        argument_expression_list        argument_expression                     default_initializer_opt
    400401%type<ifctl> conditional_declaration
    401 %type<fctl> for_control_expression              for_control_expression_list
    402 %type<compop> upupeq updown updowneq downupdowneq
    403 %type<en> subrange
     402%type<forctl> for_control_expression            for_control_expression_list
     403%type<oper> upupeq updown updowneq downupdowneq
     404%type<expr> subrange
    404405%type<decl> asm_name_opt
    405 %type<en> asm_operands_opt                              asm_operands_list                       asm_operand
    406 %type<label> label_list
    407 %type<en> asm_clobbers_list_opt
    408 %type<flag> asm_volatile_opt
    409 %type<en> handler_predicate_opt
     406%type<expr> asm_operands_opt                            asm_operands_list                       asm_operand
     407%type<labels> label_list
     408%type<expr> asm_clobbers_list_opt
     409%type<is_volatile> asm_volatile_opt
     410%type<expr> handler_predicate_opt
    410411%type<genexpr> generic_association              generic_assoc_list
    411412
    412413// statements
    413 %type<sn> statement                                             labeled_statement                       compound_statement
    414 %type<sn> statement_decl                                statement_decl_list                     statement_list_nodecl
    415 %type<sn> selection_statement                   if_statement
    416 %type<sn> switch_clause_list_opt                switch_clause_list
    417 %type<en> case_value
    418 %type<sn> case_clause                                   case_value_list                         case_label                                      case_label_list
    419 %type<sn> iteration_statement                   jump_statement
    420 %type<sn> expression_statement                  asm_statement
    421 %type<sn> with_statement
    422 %type<en> with_clause_opt
    423 %type<sn> exception_statement                   handler_clause                          finally_clause
    424 %type<catch_kind> handler_key
    425 %type<sn> mutex_statement
    426 %type<en> when_clause                                   when_clause_opt                         waitfor         waituntil               timeout
    427 %type<sn> waitfor_statement                             waituntil_statement
     414%type<stmt> statement                                           labeled_statement                       compound_statement
     415%type<stmt> statement_decl                              statement_decl_list                     statement_list_nodecl
     416%type<stmt> selection_statement                 if_statement
     417%type<clause> switch_clause_list_opt            switch_clause_list
     418%type<expr> case_value
     419%type<clause> case_clause                               case_value_list                         case_label                                      case_label_list
     420%type<stmt> iteration_statement                 jump_statement
     421%type<stmt> expression_statement                        asm_statement
     422%type<stmt> with_statement
     423%type<expr> with_clause_opt
     424%type<stmt> exception_statement
     425%type<clause> handler_clause                    finally_clause
     426%type<except_kind> handler_key
     427%type<stmt> mutex_statement
     428%type<expr> when_clause                                 when_clause_opt                         waitfor         waituntil               timeout
     429%type<stmt> waitfor_statement                           waituntil_statement
    428430%type<wfs> wor_waitfor_clause
    429 %type<wuscn> waituntil_clause                   wand_waituntil_clause       wor_waituntil_clause
     431%type<wucn> waituntil_clause                    wand_waituntil_clause       wor_waituntil_clause
    430432
    431433// declarations
     
    439441%type<decl> assertion assertion_list assertion_list_opt
    440442
    441 %type<en> bit_subrange_size_opt bit_subrange_size
     443%type<expr> bit_subrange_size_opt bit_subrange_size
    442444
    443445%type<decl> basic_declaration_specifier basic_type_name basic_type_specifier direct_type indirect_type
     
    452454
    453455%type<decl> enumerator_list enum_type enum_type_nobody
    454 %type<in> enumerator_value_opt
     456%type<init> enumerator_value_opt
    455457
    456458%type<decl> external_definition external_definition_list external_definition_list_opt
     
    459461
    460462%type<decl> field_declaration_list_opt field_declaration field_declaring_list_opt field_declarator field_abstract_list_opt field_abstract
    461 %type<en> field field_name_list field_name fraction_constants_opt
     463%type<expr> field field_name_list field_name fraction_constants_opt
    462464
    463465%type<decl> external_function_definition function_definition function_array function_declarator function_no_ptr function_ptr
     
    508510%type<decl> type_parameter type_parameter_list type_initializer_opt
    509511
    510 %type<en> type_parameters_opt type_list array_type_list
     512%type<expr> type_parameters_opt type_list array_type_list
    511513
    512514%type<decl> type_qualifier type_qualifier_name forall type_qualifier_list_opt type_qualifier_list
     
    519521
    520522// initializers
    521 %type<in>  initializer initializer_list_opt initializer_opt
     523%type<init>  initializer initializer_list_opt initializer_opt
    522524
    523525// designators
    524 %type<en>  designator designator_list designation
     526%type<expr>  designator designator_list designation
    525527
    526528
     
    644646
    645647string_literal:
    646         string_literal_list                                                     { $$ = build_constantStr( yylloc, *$1 ); }
     648        string_literal_list                                                     { $$ = new ExpressionNode( build_constantStr( yylloc, *$1 ) ); }
    647649        ;
    648650
     
    739741                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, $3 ) ); }
    740742        | string_literal '[' assignment_expression ']'          // "abc"[3], 3["abc"]
    741                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, new ExpressionNode( $1 ), $3 ) ); }
     743                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, $3 ) ); }
    742744        | postfix_expression '{' argument_expression_list_opt '}' // CFA, constructor call
    743745                {
     
    757759                { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); }
    758760        | string_literal '`' identifier                                         // CFA, postfix call
    759                 { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), new ExpressionNode( $1 ) ) ); }
     761                { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); }
    760762        | postfix_expression '.' identifier
    761763                { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_varref( yylloc, $3 ) ) ); }
     
    857859        | constant
    858860        | string_literal
    859                 { $$ = new ExpressionNode( $1 ); }
     861                { $$ = $1; }
    860862        | EXTENSION cast_expression                                                     // GCC
    861863                { $$ = $2->set_extension( true ); }
     
    12601262
    12611263case_value_list:                                                                                // CFA
    1262         case_value                                                                      { $$ = new StatementNode( build_case( $1 ) ); }
     1264        case_value                                                                      { $$ = new ClauseNode( build_case( yylloc, $1 ) ); }
    12631265                // convert case list, e.g., "case 1, 3, 5:" into "case 1: case 3: case 5"
    1264         | case_value_list ',' case_value                        { $$ = (StatementNode *)($1->set_last( new StatementNode( build_case( $3 ) ) ) ); }
     1266        | case_value_list ',' case_value                        { $$ = $1->set_last( new ClauseNode( build_case( yylloc, $3 ) ) ); }
    12651267        ;
    12661268
     
    12711273        | CASE case_value_list error                                            // syntax error
    12721274                { SemanticError( yylloc, "Missing colon after case list." ); $$ = nullptr; }
    1273         | DEFAULT ':'                                                           { $$ = new StatementNode( build_default( yylloc ) ); }
     1275        | DEFAULT ':'                                                           { $$ = new ClauseNode( build_default( yylloc ) ); }
    12741276                // A semantic check is required to ensure only one default clause per switch/choose statement.
    12751277        | DEFAULT error                                                                         //  syntax error
     
    12791281case_label_list:                                                                                // CFA
    12801282        case_label
    1281         | case_label_list case_label                            { $$ = (StatementNode *)( $1->set_last( $2 )); }
     1283        | case_label_list case_label                            { $$ = $1->set_last( $2 ); }
    12821284        ;
    12831285
     
    12961298                { $$ = $1->append_last_case( new StatementNode( build_compound( yylloc, $2 ) ) ); }
    12971299        | switch_clause_list case_label_list statement_list_nodecl
    1298                 { $$ = (StatementNode *)( $1->set_last( $2->append_last_case( new StatementNode( build_compound( yylloc, $3 ) ) ) ) ); }
     1300                { $$ = $1->set_last( $2->append_last_case( new StatementNode( build_compound( yylloc, $3 ) ) ) ); }
    12991301        ;
    13001302
     
    16791681
    16801682waituntil:
    1681         WAITUNTIL '(' cast_expression ')'
     1683        WAITUNTIL '(' comma_expression ')'
    16821684                { $$ = $3; }
    16831685        ;
     
    17361738handler_clause:
    17371739        handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement
    1738                 { $$ = new StatementNode( build_catch( yylloc, $1, $4, $6, $8 ) ); }
     1740                { $$ = new ClauseNode( build_catch( yylloc, $1, $4, $6, $8 ) ); }
    17391741        | handler_clause handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement
    1740                 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( yylloc, $2, $5, $7, $9 ) ) ); }
     1742                { $$ = $1->set_last( new ClauseNode( build_catch( yylloc, $2, $5, $7, $9 ) ) ); }
    17411743        ;
    17421744
     
    17551757
    17561758finally_clause:
    1757         FINALLY compound_statement                                      { $$ = new StatementNode( build_finally( yylloc, $2 ) ); }
     1759        FINALLY compound_statement                                      { $$ = new ClauseNode( build_finally( yylloc, $2 ) ); }
    17581760        ;
    17591761
     
    18131815asm_operand:                                                                                    // GCC
    18141816        string_literal '(' constant_expression ')'
    1815                 { $$ = new ExpressionNode( new ast::AsmExpr( yylloc, "", $1, maybeMoveBuild( $3 ) ) ); }
     1817                { $$ = new ExpressionNode( new ast::AsmExpr( yylloc, "", maybeMoveBuild( $1 ), maybeMoveBuild( $3 ) ) ); }
    18161818        | '[' IDENTIFIER ']' string_literal '(' constant_expression ')'
    18171819                {
    1818                         $$ = new ExpressionNode( new ast::AsmExpr( yylloc, *$2.str, $4, maybeMoveBuild( $6 ) ) );
     1820                        $$ = new ExpressionNode( new ast::AsmExpr( yylloc, *$2.str, maybeMoveBuild( $4 ), maybeMoveBuild( $6 ) ) );
    18191821                        delete $2.str;
    18201822                }
     
    18251827                { $$ = nullptr; }                                                               // use default argument
    18261828        | string_literal
    1827                 { $$ = new ExpressionNode( $1 ); }
     1829                { $$ = $1; }
    18281830        | asm_clobbers_list_opt ',' string_literal
    1829                 { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( $3 ) )); }
     1831                { $$ = (ExpressionNode *)( $1->set_last( $3 ) ); }
    18301832        ;
    18311833
     
    18991901static_assert:
    19001902        STATICASSERT '(' constant_expression ',' string_literal ')' ';' // C11
    1901                 { $$ = DeclarationNode::newStaticAssert( $3, $5 ); }
     1903                { $$ = DeclarationNode::newStaticAssert( $3, maybeMoveBuild( $5 ) ); }
    19021904        | STATICASSERT '(' constant_expression ')' ';'          // CFA
    19031905                { $$ = DeclarationNode::newStaticAssert( $3, build_constantStr( yylloc, *new string( "\"\"" ) ) ); }
     
    33293331                {
    33303332                        DeclarationNode * name = new DeclarationNode();
    3331                         name->asmName = $3;
     3333                        name->asmName = maybeMoveBuild( $3 );
    33323334                        $$ = name->addQualifiers( $5 );
    33333335                }
  • src/Parser/parserutility.h

    ra50fdfb r6e1e2d0  
    2424
    2525template< typename T >
    26 static inline auto maybeBuild( const T *orig ) -> decltype(orig->build()) {
     26static inline auto maybeBuild( T * orig ) -> decltype(orig->build()) {
    2727        return (orig) ? orig->build() : nullptr;
    2828}
    2929
    3030template< typename T >
    31 static inline auto maybeMoveBuild( const T *orig ) -> decltype(orig->build()) {
     31static inline auto maybeMoveBuild( T * orig ) -> decltype(orig->build()) {
    3232        auto ret = maybeBuild<T>(orig);
    3333        delete orig;
  • src/ResolvExpr/CandidateFinder.cpp

    ra50fdfb r6e1e2d0  
    5555namespace ResolvExpr {
    5656
     57/// Unique identifier for matching expression resolutions to their requesting expression
     58UniqueId globalResnSlot = 0;
     59
     60namespace {
     61        /// First index is which argument, second is which alternative, third is which exploded element
     62        using ExplodedArgs_new = std::deque< std::vector< ExplodedArg > >;
     63
     64        /// Returns a list of alternatives with the minimum cost in the given list
     65        CandidateList findMinCost( const CandidateList & candidates ) {
     66                CandidateList out;
     67                Cost minCost = Cost::infinity;
     68                for ( const CandidateRef & r : candidates ) {
     69                        if ( r->cost < minCost ) {
     70                                minCost = r->cost;
     71                                out.clear();
     72                                out.emplace_back( r );
     73                        } else if ( r->cost == minCost ) {
     74                                out.emplace_back( r );
     75                        }
     76                }
     77                return out;
     78        }
     79
     80        /// Computes conversion cost for a given expression to a given type
     81        const ast::Expr * computeExpressionConversionCost(
     82                const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost
     83        ) {
     84                Cost convCost = computeConversionCost(
     85                                arg->result, paramType, arg->get_lvalue(), symtab, env );
     86                outCost += convCost;
     87
     88                // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires
     89                // conversion. Ignore poly cost for now, since this requires resolution of the cast to
     90                // infer parameters and this does not currently work for the reason stated below
     91                Cost tmpCost = convCost;
     92                tmpCost.incPoly( -tmpCost.get_polyCost() );
     93                if ( tmpCost != Cost::zero ) {
     94                        ast::ptr< ast::Type > newType = paramType;
     95                        env.apply( newType );
     96                        return new ast::CastExpr{ arg, newType };
     97
     98                        // xxx - *should* be able to resolve this cast, but at the moment pointers are not
     99                        // castable to zero_t, but are implicitly convertible. This is clearly inconsistent,
     100                        // once this is fixed it should be possible to resolve the cast.
     101                        // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable,
     102                        // but it shouldn't be because this makes the conversion from DT* to DT* since
     103                        // commontype(zero_t, DT*) is DT*, rather than nothing
     104
     105                        // CandidateFinder finder{ symtab, env };
     106                        // finder.find( arg, ResolvMode::withAdjustment() );
     107                        // assertf( finder.candidates.size() > 0,
     108                        //      "Somehow castable expression failed to find alternatives." );
     109                        // assertf( finder.candidates.size() == 1,
     110                        //      "Somehow got multiple alternatives for known cast expression." );
     111                        // return finder.candidates.front()->expr;
     112                }
     113
     114                return arg;
     115        }
     116
     117        /// Computes conversion cost for a given candidate
     118        Cost computeApplicationConversionCost(
     119                CandidateRef cand, const ast::SymbolTable & symtab
     120        ) {
     121                auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >();
     122                auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
     123                auto function = pointer->base.strict_as< ast::FunctionType >();
     124
     125                Cost convCost = Cost::zero;
     126                const auto & params = function->params;
     127                auto param = params.begin();
     128                auto & args = appExpr->args;
     129
     130                for ( unsigned i = 0; i < args.size(); ++i ) {
     131                        const ast::Type * argType = args[i]->result;
     132                        PRINT(
     133                                std::cerr << "arg expression:" << std::endl;
     134                                ast::print( std::cerr, args[i], 2 );
     135                                std::cerr << "--- results are" << std::endl;
     136                                ast::print( std::cerr, argType, 2 );
     137                        )
     138
     139                        if ( param == params.end() ) {
     140                                if ( function->isVarArgs ) {
     141                                        convCost.incUnsafe();
     142                                        PRINT( std::cerr << "end of params with varargs function: inc unsafe: "
     143                                                << convCost << std::endl; ; )
     144                                        // convert reference-typed expressions into value-typed expressions
     145                                        cand->expr = ast::mutate_field_index(
     146                                                appExpr, &ast::ApplicationExpr::args, i,
     147                                                referenceToRvalueConversion( args[i], convCost ) );
     148                                        continue;
     149                                } else return Cost::infinity;
     150                        }
     151
     152                        if ( auto def = args[i].as< ast::DefaultArgExpr >() ) {
     153                                // Default arguments should be free - don't include conversion cost.
     154                                // Unwrap them here because they are not relevant to the rest of the system
     155                                cand->expr = ast::mutate_field_index(
     156                                        appExpr, &ast::ApplicationExpr::args, i, def->expr );
     157                                ++param;
     158                                continue;
     159                        }
     160
     161                        // mark conversion cost and also specialization cost of param type
     162                        // const ast::Type * paramType = (*param)->get_type();
     163                        cand->expr = ast::mutate_field_index(
     164                                appExpr, &ast::ApplicationExpr::args, i,
     165                                computeExpressionConversionCost(
     166                                        args[i], *param, symtab, cand->env, convCost ) );
     167                        convCost.decSpec( specCost( *param ) );
     168                        ++param;  // can't be in for-loop update because of the continue
     169                }
     170
     171                if ( param != params.end() ) return Cost::infinity;
     172
     173                // specialization cost of return types can't be accounted for directly, it disables
     174                // otherwise-identical calls, like this example based on auto-newline in the I/O lib:
     175                //
     176                //   forall(otype OS) {
     177                //     void ?|?(OS&, int);  // with newline
     178                //     OS&  ?|?(OS&, int);  // no newline, always chosen due to more specialization
     179                //   }
     180
     181                // mark type variable and specialization cost of forall clause
     182                convCost.incVar( function->forall.size() );
     183                convCost.decSpec( function->assertions.size() );
     184
     185                return convCost;
     186        }
     187
     188        void makeUnifiableVars(
     189                const ast::FunctionType * type, ast::OpenVarSet & unifiableVars,
     190                ast::AssertionSet & need
     191        ) {
     192                for ( auto & tyvar : type->forall ) {
     193                        unifiableVars[ *tyvar ] = ast::TypeData{ tyvar->base };
     194                }
     195                for ( auto & assn : type->assertions ) {
     196                        need[ assn ].isUsed = true;
     197                }
     198        }
     199
     200        /// Gets a default value from an initializer, nullptr if not present
     201        const ast::ConstantExpr * getDefaultValue( const ast::Init * init ) {
     202                if ( auto si = dynamic_cast< const ast::SingleInit * >( init ) ) {
     203                        if ( auto ce = si->value.as< ast::CastExpr >() ) {
     204                                return ce->arg.as< ast::ConstantExpr >();
     205                        } else {
     206                                return si->value.as< ast::ConstantExpr >();
     207                        }
     208                }
     209                return nullptr;
     210        }
     211
     212        /// State to iteratively build a match of parameter expressions to arguments
     213        struct ArgPack {
     214                std::size_t parent;          ///< Index of parent pack
     215                ast::ptr< ast::Expr > expr;  ///< The argument stored here
     216                Cost cost;                   ///< The cost of this argument
     217                ast::TypeEnvironment env;    ///< Environment for this pack
     218                ast::AssertionSet need;      ///< Assertions outstanding for this pack
     219                ast::AssertionSet have;      ///< Assertions found for this pack
     220                ast::OpenVarSet open;        ///< Open variables for this pack
     221                unsigned nextArg;            ///< Index of next argument in arguments list
     222                unsigned tupleStart;         ///< Number of tuples that start at this index
     223                unsigned nextExpl;           ///< Index of next exploded element
     224                unsigned explAlt;            ///< Index of alternative for nextExpl > 0
     225
     226                ArgPack()
     227                : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ),
     228                  tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
     229
     230                ArgPack(
     231                        const ast::TypeEnvironment & env, const ast::AssertionSet & need,
     232                        const ast::AssertionSet & have, const ast::OpenVarSet & open )
     233                : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),
     234                  open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
     235
     236                ArgPack(
     237                        std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,
     238                        ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,
     239                        unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,
     240                        unsigned nextExpl = 0, unsigned explAlt = 0 )
     241                : parent(parent), expr( expr ), cost( cost ), env( std::move( env ) ), need( std::move( need ) ),
     242                  have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),
     243                  nextExpl( nextExpl ), explAlt( explAlt ) {}
     244
     245                ArgPack(
     246                        const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need,
     247                        ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added )
     248                : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( std::move( env ) ),
     249                  need( std::move( need ) ), have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ),
     250                  tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {}
     251
     252                /// true if this pack is in the middle of an exploded argument
     253                bool hasExpl() const { return nextExpl > 0; }
     254
     255                /// Gets the list of exploded candidates for this pack
     256                const ExplodedArg & getExpl( const ExplodedArgs_new & args ) const {
     257                        return args[ nextArg-1 ][ explAlt ];
     258                }
     259
     260                /// Ends a tuple expression, consolidating the appropriate args
     261                void endTuple( const std::vector< ArgPack > & packs ) {
     262                        // add all expressions in tuple to list, summing cost
     263                        std::deque< const ast::Expr * > exprs;
     264                        const ArgPack * pack = this;
     265                        if ( expr ) { exprs.emplace_front( expr ); }
     266                        while ( pack->tupleStart == 0 ) {
     267                                pack = &packs[pack->parent];
     268                                exprs.emplace_front( pack->expr );
     269                                cost += pack->cost;
     270                        }
     271                        // reset pack to appropriate tuple
     272                        std::vector< ast::ptr< ast::Expr > > exprv( exprs.begin(), exprs.end() );
     273                        expr = new ast::TupleExpr{ expr->location, std::move( exprv ) };
     274                        tupleStart = pack->tupleStart - 1;
     275                        parent = pack->parent;
     276                }
     277        };
     278
     279        /// Instantiates an argument to match a parameter, returns false if no matching results left
     280        bool instantiateArgument(
     281                const CodeLocation & location,
     282                const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args,
     283                std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,
     284                unsigned nTuples = 0
     285        ) {
     286                if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) {
     287                        // paramType is a TupleType -- group args into a TupleExpr
     288                        ++nTuples;
     289                        for ( const ast::Type * type : *tupleType ) {
     290                                // xxx - dropping initializer changes behaviour from previous, but seems correct
     291                                // ^^^ need to handle the case where a tuple has a default argument
     292                                if ( ! instantiateArgument( location,
     293                                        type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;
     294                                nTuples = 0;
     295                        }
     296                        // re-constitute tuples for final generation
     297                        for ( auto i = genStart; i < results.size(); ++i ) {
     298                                results[i].endTuple( results );
     299                        }
     300                        return true;
     301                } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) {
     302                        // paramType is a ttype, consumes all remaining arguments
     303
     304                        // completed tuples; will be spliced to end of results to finish
     305                        std::vector< ArgPack > finalResults{};
     306
     307                        // iterate until all results completed
     308                        std::size_t genEnd;
     309                        ++nTuples;
     310                        do {
     311                                genEnd = results.size();
     312
     313                                // add another argument to results
     314                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
     315                                        unsigned nextArg = results[i].nextArg;
     316
     317                                        // use next element of exploded tuple if present
     318                                        if ( results[i].hasExpl() ) {
     319                                                const ExplodedArg & expl = results[i].getExpl( args );
     320
     321                                                unsigned nextExpl = results[i].nextExpl + 1;
     322                                                if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
     323
     324                                                results.emplace_back(
     325                                                        i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
     326                                                        copy( results[i].need ), copy( results[i].have ),
     327                                                        copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl,
     328                                                        results[i].explAlt );
     329
     330                                                continue;
     331                                        }
     332
     333                                        // finish result when out of arguments
     334                                        if ( nextArg >= args.size() ) {
     335                                                ArgPack newResult{
     336                                                        results[i].env, results[i].need, results[i].have, results[i].open };
     337                                                newResult.nextArg = nextArg;
     338                                                const ast::Type * argType = nullptr;
     339
     340                                                if ( nTuples > 0 || ! results[i].expr ) {
     341                                                        // first iteration or no expression to clone,
     342                                                        // push empty tuple expression
     343                                                        newResult.parent = i;
     344                                                        newResult.expr = new ast::TupleExpr( location, {} );
     345                                                        argType = newResult.expr->result;
     346                                                } else {
     347                                                        // clone result to collect tuple
     348                                                        newResult.parent = results[i].parent;
     349                                                        newResult.cost = results[i].cost;
     350                                                        newResult.tupleStart = results[i].tupleStart;
     351                                                        newResult.expr = results[i].expr;
     352                                                        argType = newResult.expr->result;
     353
     354                                                        if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) {
     355                                                                // the case where a ttype value is passed directly is special,
     356                                                                // e.g. for argument forwarding purposes
     357                                                                // xxx - what if passing multiple arguments, last of which is
     358                                                                //       ttype?
     359                                                                // xxx - what would happen if unify was changed so that unifying
     360                                                                //       tuple
     361                                                                // types flattened both before unifying lists? then pass in
     362                                                                // TupleType (ttype) below.
     363                                                                --newResult.tupleStart;
     364                                                        } else {
     365                                                                // collapse leftover arguments into tuple
     366                                                                newResult.endTuple( results );
     367                                                                argType = newResult.expr->result;
     368                                                        }
     369                                                }
     370
     371                                                // check unification for ttype before adding to final
     372                                                if (
     373                                                        unify(
     374                                                                ttype, argType, newResult.env, newResult.need, newResult.have,
     375                                                                newResult.open, symtab )
     376                                                ) {
     377                                                        finalResults.emplace_back( std::move( newResult ) );
     378                                                }
     379
     380                                                continue;
     381                                        }
     382
     383                                        // add each possible next argument
     384                                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
     385                                                const ExplodedArg & expl = args[nextArg][j];
     386
     387                                                // fresh copies of parent parameters for this iteration
     388                                                ast::TypeEnvironment env = results[i].env;
     389                                                ast::OpenVarSet open = results[i].open;
     390
     391                                                env.addActual( expl.env, open );
     392
     393                                                // skip empty tuple arguments by (nearly) cloning parent into next gen
     394                                                if ( expl.exprs.empty() ) {
     395                                                        results.emplace_back(
     396                                                                results[i], std::move( env ), copy( results[i].need ),
     397                                                                copy( results[i].have ), std::move( open ), nextArg + 1, expl.cost );
     398
     399                                                        continue;
     400                                                }
     401
     402                                                // add new result
     403                                                results.emplace_back(
     404                                                        i, expl.exprs.front(), std::move( env ), copy( results[i].need ),
     405                                                        copy( results[i].have ), std::move( open ), nextArg + 1, nTuples,
     406                                                        expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
     407                                        }
     408                                }
     409
     410                                // reset for next round
     411                                genStart = genEnd;
     412                                nTuples = 0;
     413                        } while ( genEnd != results.size() );
     414
     415                        // splice final results onto results
     416                        for ( std::size_t i = 0; i < finalResults.size(); ++i ) {
     417                                results.emplace_back( std::move( finalResults[i] ) );
     418                        }
     419                        return ! finalResults.empty();
     420                }
     421
     422                // iterate each current subresult
     423                std::size_t genEnd = results.size();
     424                for ( std::size_t i = genStart; i < genEnd; ++i ) {
     425                        unsigned nextArg = results[i].nextArg;
     426
     427                        // use remainder of exploded tuple if present
     428                        if ( results[i].hasExpl() ) {
     429                                const ExplodedArg & expl = results[i].getExpl( args );
     430                                const ast::Expr * expr = expl.exprs[ results[i].nextExpl ];
     431
     432                                ast::TypeEnvironment env = results[i].env;
     433                                ast::AssertionSet need = results[i].need, have = results[i].have;
     434                                ast::OpenVarSet open = results[i].open;
     435
     436                                const ast::Type * argType = expr->result;
     437
     438                                PRINT(
     439                                        std::cerr << "param type is ";
     440                                        ast::print( std::cerr, paramType );
     441                                        std::cerr << std::endl << "arg type is ";
     442                                        ast::print( std::cerr, argType );
     443                                        std::cerr << std::endl;
     444                                )
     445
     446                                if ( unify( paramType, argType, env, need, have, open, symtab ) ) {
     447                                        unsigned nextExpl = results[i].nextExpl + 1;
     448                                        if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
     449
     450                                        results.emplace_back(
     451                                                i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), nextArg,
     452                                                nTuples, Cost::zero, nextExpl, results[i].explAlt );
     453                                }
     454
     455                                continue;
     456                        }
     457
     458                        // use default initializers if out of arguments
     459                        if ( nextArg >= args.size() ) {
     460                                if ( const ast::ConstantExpr * cnst = getDefaultValue( init ) ) {
     461                                        ast::TypeEnvironment env = results[i].env;
     462                                        ast::AssertionSet need = results[i].need, have = results[i].have;
     463                                        ast::OpenVarSet open = results[i].open;
     464
     465                                        if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) {
     466                                                results.emplace_back(
     467                                                        i, new ast::DefaultArgExpr{ cnst->location, cnst }, std::move( env ),
     468                                                        std::move( need ), std::move( have ), std::move( open ), nextArg, nTuples );
     469                                        }
     470                                }
     471
     472                                continue;
     473                        }
     474
     475                        // Check each possible next argument
     476                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
     477                                const ExplodedArg & expl = args[nextArg][j];
     478
     479                                // fresh copies of parent parameters for this iteration
     480                                ast::TypeEnvironment env = results[i].env;
     481                                ast::AssertionSet need = results[i].need, have = results[i].have;
     482                                ast::OpenVarSet open = results[i].open;
     483
     484                                env.addActual( expl.env, open );
     485
     486                                // skip empty tuple arguments by (nearly) cloning parent into next gen
     487                                if ( expl.exprs.empty() ) {
     488                                        results.emplace_back(
     489                                                results[i], std::move( env ), std::move( need ), std::move( have ), std::move( open ),
     490                                                nextArg + 1, expl.cost );
     491
     492                                        continue;
     493                                }
     494
     495                                // consider only first exploded arg
     496                                const ast::Expr * expr = expl.exprs.front();
     497                                const ast::Type * argType = expr->result;
     498
     499                                PRINT(
     500                                        std::cerr << "param type is ";
     501                                        ast::print( std::cerr, paramType );
     502                                        std::cerr << std::endl << "arg type is ";
     503                                        ast::print( std::cerr, argType );
     504                                        std::cerr << std::endl;
     505                                )
     506
     507                                // attempt to unify types
     508                                if ( unify( paramType, argType, env, need, have, open, symtab ) ) {
     509                                        // add new result
     510                                        results.emplace_back(
     511                                                i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
     512                                                nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
     513                                }
     514                        }
     515                }
     516
     517                // reset for next parameter
     518                genStart = genEnd;
     519
     520                return genEnd != results.size();  // were any new results added?
     521        }
     522
     523        /// Generate a cast expression from `arg` to `toType`
     524        const ast::Expr * restructureCast(
     525                ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast
     526        ) {
     527                if (
     528                        arg->result->size() > 1
     529                        && ! toType->isVoid()
     530                        && ! dynamic_cast< const ast::ReferenceType * >( toType )
     531                ) {
     532                        // Argument is a tuple and the target type is neither void nor a reference. Cast each
     533                        // member of the tuple to its corresponding target type, producing the tuple of those
     534                        // cast expressions. If there are more components of the tuple than components in the
     535                        // target type, then excess components do not come out in the result expression (but
     536                        // UniqueExpr ensures that the side effects will still be produced)
     537                        if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
     538                                // expressions which may contain side effects require a single unique instance of
     539                                // the expression
     540                                arg = new ast::UniqueExpr{ arg->location, arg };
     541                        }
     542                        std::vector< ast::ptr< ast::Expr > > components;
     543                        for ( unsigned i = 0; i < toType->size(); ++i ) {
     544                                // cast each component
     545                                ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i };
     546                                components.emplace_back(
     547                                        restructureCast( idx, toType->getComponent( i ), isGenerated ) );
     548                        }
     549                        return new ast::TupleExpr{ arg->location, std::move( components ) };
     550                } else {
     551                        // handle normally
     552                        return new ast::CastExpr{ arg->location, arg, toType, isGenerated };
     553                }
     554        }
     555
     556        /// Gets the name from an untyped member expression (must be NameExpr)
     557        const std::string & getMemberName( const ast::UntypedMemberExpr * memberExpr ) {
     558                if ( memberExpr->member.as< ast::ConstantExpr >() ) {
     559                        SemanticError( memberExpr, "Indexed access to struct fields unsupported: " );
     560                }
     561
     562                return memberExpr->member.strict_as< ast::NameExpr >()->name;
     563        }
     564
     565        /// Actually visits expressions to find their candidate interpretations
     566        class Finder final : public ast::WithShortCircuiting {
     567                const ResolveContext & context;
     568                const ast::SymbolTable & symtab;
     569        public:
     570                // static size_t traceId;
     571                CandidateFinder & selfFinder;
     572                CandidateList & candidates;
     573                const ast::TypeEnvironment & tenv;
     574                ast::ptr< ast::Type > & targetType;
     575
     576                enum Errors {
     577                        NotFound,
     578                        NoMatch,
     579                        ArgsToFew,
     580                        ArgsToMany,
     581                        RetsToFew,
     582                        RetsToMany,
     583                        NoReason
     584                };
     585
     586                struct {
     587                        Errors code = NotFound;
     588                } reason;
     589
     590                Finder( CandidateFinder & f )
     591                : context( f.context ), symtab( context.symtab ), selfFinder( f ),
     592                  candidates( f.candidates ), tenv( f.env ), targetType( f.targetType ) {}
     593
     594                void previsit( const ast::Node * ) { visit_children = false; }
     595
     596                /// Convenience to add candidate to list
     597                template<typename... Args>
     598                void addCandidate( Args &&... args ) {
     599                        candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } );
     600                        reason.code = NoReason;
     601                }
     602
     603                void postvisit( const ast::ApplicationExpr * applicationExpr ) {
     604                        addCandidate( applicationExpr, tenv );
     605                }
     606
     607                /// Set up candidate assertions for inference
     608                void inferParameters( CandidateRef & newCand, CandidateList & out );
     609
     610                /// Completes a function candidate with arguments located
     611                void validateFunctionCandidate(
     612                        const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,
     613                        CandidateList & out );
     614
     615                /// Builds a list of candidates for a function, storing them in out
     616                void makeFunctionCandidates(
     617                        const CodeLocation & location,
     618                        const CandidateRef & func, const ast::FunctionType * funcType,
     619                        const ExplodedArgs_new & args, CandidateList & out );
     620
     621                /// Adds implicit struct-conversions to the alternative list
     622                void addAnonConversions( const CandidateRef & cand );
     623
     624                /// Adds aggregate member interpretations
     625                void addAggMembers(
     626                        const ast::BaseInstType * aggrInst, const ast::Expr * expr,
     627                        const Candidate & cand, const Cost & addedCost, const std::string & name
     628                );
     629
     630                /// Adds tuple member interpretations
     631                void addTupleMembers(
     632                        const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,
     633                        const Cost & addedCost, const ast::Expr * member
     634                );
     635
     636                /// true if expression is an lvalue
     637                static bool isLvalue( const ast::Expr * x ) {
     638                        return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() );
     639                }
     640
     641                void postvisit( const ast::UntypedExpr * untypedExpr );
     642                void postvisit( const ast::VariableExpr * variableExpr );
     643                void postvisit( const ast::ConstantExpr * constantExpr );
     644                void postvisit( const ast::SizeofExpr * sizeofExpr );
     645                void postvisit( const ast::AlignofExpr * alignofExpr );
     646                void postvisit( const ast::AddressExpr * addressExpr );
     647                void postvisit( const ast::LabelAddressExpr * labelExpr );
     648                void postvisit( const ast::CastExpr * castExpr );
     649                void postvisit( const ast::VirtualCastExpr * castExpr );
     650                void postvisit( const ast::KeywordCastExpr * castExpr );
     651                void postvisit( const ast::UntypedMemberExpr * memberExpr );
     652                void postvisit( const ast::MemberExpr * memberExpr );
     653                void postvisit( const ast::NameExpr * nameExpr );
     654                void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr );
     655                void postvisit( const ast::OffsetofExpr * offsetofExpr );
     656                void postvisit( const ast::OffsetPackExpr * offsetPackExpr );
     657                void postvisit( const ast::LogicalExpr * logicalExpr );
     658                void postvisit( const ast::ConditionalExpr * conditionalExpr );
     659                void postvisit( const ast::CommaExpr * commaExpr );
     660                void postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr );
     661                void postvisit( const ast::ConstructorExpr * ctorExpr );
     662                void postvisit( const ast::RangeExpr * rangeExpr );
     663                void postvisit( const ast::UntypedTupleExpr * tupleExpr );
     664                void postvisit( const ast::TupleExpr * tupleExpr );
     665                void postvisit( const ast::TupleIndexExpr * tupleExpr );
     666                void postvisit( const ast::TupleAssignExpr * tupleExpr );
     667                void postvisit( const ast::UniqueExpr * unqExpr );
     668                void postvisit( const ast::StmtExpr * stmtExpr );
     669                void postvisit( const ast::UntypedInitExpr * initExpr );
     670
     671                void postvisit( const ast::InitExpr * ) {
     672                        assertf( false, "CandidateFinder should never see a resolved InitExpr." );
     673                }
     674
     675                void postvisit( const ast::DeletedExpr * ) {
     676                        assertf( false, "CandidateFinder should never see a DeletedExpr." );
     677                }
     678
     679                void postvisit( const ast::GenericExpr * ) {
     680                        assertf( false, "_Generic is not yet supported." );
     681                }
     682        };
     683
     684        /// Set up candidate assertions for inference
     685        void Finder::inferParameters( CandidateRef & newCand, CandidateList & out ) {
     686                // Set need bindings for any unbound assertions
     687                UniqueId crntResnSlot = 0; // matching ID for this expression's assertions
     688                for ( auto & assn : newCand->need ) {
     689                        // skip already-matched assertions
     690                        if ( assn.second.resnSlot != 0 ) continue;
     691                        // assign slot for expression if needed
     692                        if ( crntResnSlot == 0 ) { crntResnSlot = ++globalResnSlot; }
     693                        // fix slot to assertion
     694                        assn.second.resnSlot = crntResnSlot;
     695                }
     696                // pair slot to expression
     697                if ( crntResnSlot != 0 ) {
     698                        newCand->expr.get_and_mutate()->inferred.resnSlots().emplace_back( crntResnSlot );
     699                }
     700
     701                // add to output list; assertion satisfaction will occur later
     702                out.emplace_back( newCand );
     703        }
     704
     705        /// Completes a function candidate with arguments located
     706        void Finder::validateFunctionCandidate(
     707                const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,
     708                CandidateList & out
     709        ) {
     710                ast::ApplicationExpr * appExpr =
     711                        new ast::ApplicationExpr{ func->expr->location, func->expr };
     712                // sum cost and accumulate arguments
     713                std::deque< const ast::Expr * > args;
     714                Cost cost = func->cost;
     715                const ArgPack * pack = &result;
     716                while ( pack->expr ) {
     717                        args.emplace_front( pack->expr );
     718                        cost += pack->cost;
     719                        pack = &results[pack->parent];
     720                }
     721                std::vector< ast::ptr< ast::Expr > > vargs( args.begin(), args.end() );
     722                appExpr->args = std::move( vargs );
     723                // build and validate new candidate
     724                auto newCand =
     725                        std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost );
     726                PRINT(
     727                        std::cerr << "instantiate function success: " << appExpr << std::endl;
     728                        std::cerr << "need assertions:" << std::endl;
     729                        ast::print( std::cerr, result.need, 2 );
     730                )
     731                inferParameters( newCand, out );
     732        }
     733
     734        /// Builds a list of candidates for a function, storing them in out
     735        void Finder::makeFunctionCandidates(
     736                const CodeLocation & location,
     737                const CandidateRef & func, const ast::FunctionType * funcType,
     738                const ExplodedArgs_new & args, CandidateList & out
     739        ) {
     740                ast::OpenVarSet funcOpen;
     741                ast::AssertionSet funcNeed, funcHave;
     742                ast::TypeEnvironment funcEnv{ func->env };
     743                makeUnifiableVars( funcType, funcOpen, funcNeed );
     744                // add all type variables as open variables now so that those not used in the
     745                // parameter list are still considered open
     746                funcEnv.add( funcType->forall );
     747
     748                if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) {
     749                        // attempt to narrow based on expected target type
     750                        const ast::Type * returnType = funcType->returns.front();
     751                        if ( ! unify(
     752                                returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab )
     753                        ) {
     754                                // unification failed, do not pursue this candidate
     755                                return;
     756                        }
     757                }
     758
     759                // iteratively build matches, one parameter at a time
     760                std::vector< ArgPack > results;
     761                results.emplace_back( funcEnv, funcNeed, funcHave, funcOpen );
     762                std::size_t genStart = 0;
     763
     764                // xxx - how to handle default arg after change to ftype representation?
     765                if (const ast::VariableExpr * varExpr = func->expr.as<ast::VariableExpr>()) {
     766                        if (const ast::FunctionDecl * funcDecl = varExpr->var.as<ast::FunctionDecl>()) {
     767                                // function may have default args only if directly calling by name
     768                                // must use types on candidate however, due to RenameVars substitution
     769                                auto nParams = funcType->params.size();
     770
     771                                for (size_t i=0; i<nParams; ++i) {
     772                                        auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>();
     773                                        if (!instantiateArgument( location,
     774                                                funcType->params[i], obj->init, args, results, genStart, symtab)) return;
     775                                }
     776                                goto endMatch;
     777                        }
     778                }
     779                for ( const auto & param : funcType->params ) {
     780                        // Try adding the arguments corresponding to the current parameter to the existing
     781                        // matches
     782                        // no default args for indirect calls
     783                        if ( ! instantiateArgument( location,
     784                                param, nullptr, args, results, genStart, symtab ) ) return;
     785                }
     786
     787                endMatch:
     788                if ( funcType->isVarArgs ) {
     789                        // append any unused arguments to vararg pack
     790                        std::size_t genEnd;
     791                        do {
     792                                genEnd = results.size();
     793
     794                                // iterate results
     795                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
     796                                        unsigned nextArg = results[i].nextArg;
     797
     798                                        // use remainder of exploded tuple if present
     799                                        if ( results[i].hasExpl() ) {
     800                                                const ExplodedArg & expl = results[i].getExpl( args );
     801
     802                                                unsigned nextExpl = results[i].nextExpl + 1;
     803                                                if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
     804
     805                                                results.emplace_back(
     806                                                        i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
     807                                                        copy( results[i].need ), copy( results[i].have ),
     808                                                        copy( results[i].open ), nextArg, 0, Cost::zero, nextExpl,
     809                                                        results[i].explAlt );
     810
     811                                                continue;
     812                                        }
     813
     814                                        // finish result when out of arguments
     815                                        if ( nextArg >= args.size() ) {
     816                                                validateFunctionCandidate( func, results[i], results, out );
     817
     818                                                continue;
     819                                        }
     820
     821                                        // add each possible next argument
     822                                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
     823                                                const ExplodedArg & expl = args[nextArg][j];
     824
     825                                                // fresh copies of parent parameters for this iteration
     826                                                ast::TypeEnvironment env = results[i].env;
     827                                                ast::OpenVarSet open = results[i].open;
     828
     829                                                env.addActual( expl.env, open );
     830
     831                                                // skip empty tuple arguments by (nearly) cloning parent into next gen
     832                                                if ( expl.exprs.empty() ) {
     833                                                        results.emplace_back(
     834                                                                results[i], std::move( env ), copy( results[i].need ),
     835                                                                copy( results[i].have ), std::move( open ), nextArg + 1,
     836                                                                expl.cost );
     837
     838                                                        continue;
     839                                                }
     840
     841                                                // add new result
     842                                                results.emplace_back(
     843                                                        i, expl.exprs.front(), std::move( env ), copy( results[i].need ),
     844                                                        copy( results[i].have ), std::move( open ), nextArg + 1, 0, expl.cost,
     845                                                        expl.exprs.size() == 1 ? 0 : 1, j );
     846                                        }
     847                                }
     848
     849                                genStart = genEnd;
     850                        } while( genEnd != results.size() );
     851                } else {
     852                        // filter out the results that don't use all the arguments
     853                        for ( std::size_t i = genStart; i < results.size(); ++i ) {
     854                                ArgPack & result = results[i];
     855                                if ( ! result.hasExpl() && result.nextArg >= args.size() ) {
     856                                        validateFunctionCandidate( func, result, results, out );
     857                                }
     858                        }
     859                }
     860        }
     861
     862        /// Adds implicit struct-conversions to the alternative list
     863        void Finder::addAnonConversions( const CandidateRef & cand ) {
     864                // adds anonymous member interpretations whenever an aggregate value type is seen.
     865                // it's okay for the aggregate expression to have reference type -- cast it to the
     866                // base type to treat the aggregate as the referenced value
     867                ast::ptr< ast::Expr > aggrExpr( cand->expr );
     868                ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result;
     869                cand->env.apply( aggrType );
     870
     871                if ( aggrType.as< ast::ReferenceType >() ) {
     872                        aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() };
     873                }
     874
     875                if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) {
     876                        addAggMembers( structInst, aggrExpr, *cand, Cost::safe, "" );
     877                } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) {
     878                        addAggMembers( unionInst, aggrExpr, *cand, Cost::safe, "" );
     879                }
     880        }
     881
     882        /// Adds aggregate member interpretations
     883        void Finder::addAggMembers(
     884                const ast::BaseInstType * aggrInst, const ast::Expr * expr,
     885                const Candidate & cand, const Cost & addedCost, const std::string & name
     886        ) {
     887                for ( const ast::Decl * decl : aggrInst->lookup( name ) ) {
     888                        auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl );
     889                        CandidateRef newCand = std::make_shared<Candidate>(
     890                                cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost );
     891                        // add anonymous member interpretations whenever an aggregate value type is seen
     892                        // as a member expression
     893                        addAnonConversions( newCand );
     894                        candidates.emplace_back( std::move( newCand ) );
     895                }
     896        }
     897
     898        /// Adds tuple member interpretations
     899        void Finder::addTupleMembers(
     900                const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,
     901                const Cost & addedCost, const ast::Expr * member
     902        ) {
     903                if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) {
     904                        // get the value of the constant expression as an int, must be between 0 and the
     905                        // length of the tuple to have meaning
     906                        long long val = constantExpr->intValue();
     907                        if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {
     908                                addCandidate(
     909                                        cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val },
     910                                        addedCost );
     911                        }
     912                }
     913        }
     914
     915        void Finder::postvisit( const ast::UntypedExpr * untypedExpr ) {
     916                std::vector< CandidateFinder > argCandidates =
     917                        selfFinder.findSubExprs( untypedExpr->args );
     918
     919                // take care of possible tuple assignments
     920                // if not tuple assignment, handled as normal function call
     921                Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates );
     922
     923                CandidateFinder funcFinder( context, tenv );
     924                if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) {
     925                        auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
     926                        if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) {
     927                                assertf(!argCandidates.empty(), "special function call without argument");
     928                                for (auto & firstArgCand: argCandidates[0]) {
     929                                        ast::ptr<ast::Type> argType = firstArgCand->expr->result;
     930                                        firstArgCand->env.apply(argType);
     931                                        // strip references
     932                                        // xxx - is this correct?
     933                                        while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base;
     934
     935                                        // convert 1-tuple to plain type
     936                                        if (auto tuple = argType.as<ast::TupleType>()) {
     937                                                if (tuple->size() == 1) {
     938                                                        argType = tuple->types[0];
     939                                                }
     940                                        }
     941
     942                                        // if argType is an unbound type parameter, all special functions need to be searched.
     943                                        if (isUnboundType(argType)) {
     944                                                funcFinder.otypeKeys.clear();
     945                                                break;
     946                                        }
     947
     948                                        if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer);                                             
     949                                        // else if (const ast::EnumInstType * enumInst = argType.as<ast::EnumInstType>()) {
     950                                        //      const ast::EnumDecl * enumDecl = enumInst->base; // Here
     951                                        //      if ( const ast::Type* enumType = enumDecl->base ) {
     952                                        //              // instance of enum (T) is a instance of type (T)
     953                                        //              funcFinder.otypeKeys.insert(Mangle::mangle(enumType, Mangle::NoGenericParams | Mangle::Type));
     954                                        //      } else {
     955                                        //              // instance of an untyped enum is techically int
     956                                        //              funcFinder.otypeKeys.insert(Mangle::mangle(enumDecl, Mangle::NoGenericParams | Mangle::Type));
     957                                        //      }
     958                                        // }
     959                                        else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type));
     960                                }
     961                        }
     962                }
     963                // if candidates are already produced, do not fail
     964                // xxx - is it possible that handleTupleAssignment and main finder both produce candidates?
     965                // this means there exists ctor/assign functions with a tuple as first parameter.
     966                ResolvMode mode = {
     967                        true, // adjust
     968                        !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name
     969                        selfFinder.candidates.empty() // failfast if other options are not found
     970                };
     971                funcFinder.find( untypedExpr->func, mode );
     972                // short-circuit if no candidates
     973                // if ( funcFinder.candidates.empty() ) return;
     974
     975                reason.code = NoMatch;
     976
     977                // find function operators
     978                ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" }; // ??? why not ?{}
     979                CandidateFinder opFinder( context, tenv );
     980                // okay if there aren't any function operations
     981                opFinder.find( opExpr, ResolvMode::withoutFailFast() );
     982                PRINT(
     983                        std::cerr << "known function ops:" << std::endl;
     984                        print( std::cerr, opFinder.candidates, 1 );
     985                )
     986
     987                // pre-explode arguments
     988                ExplodedArgs_new argExpansions;
     989                for ( const CandidateFinder & args : argCandidates ) {
     990                        argExpansions.emplace_back();
     991                        auto & argE = argExpansions.back();
     992                        for ( const CandidateRef & arg : args ) { argE.emplace_back( *arg, symtab ); }
     993                }
     994
     995                // Find function matches
     996                CandidateList found;
     997                SemanticErrorException errors;
     998                for ( CandidateRef & func : funcFinder ) {
     999                        try {
     1000                                PRINT(
     1001                                        std::cerr << "working on alternative:" << std::endl;
     1002                                        print( std::cerr, *func, 2 );
     1003                                )
     1004
     1005                                // check if the type is a pointer to function
     1006                                const ast::Type * funcResult = func->expr->result->stripReferences();
     1007                                if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) {
     1008                                        if ( auto function = pointer->base.as< ast::FunctionType >() ) {
     1009                                                CandidateRef newFunc{ new Candidate{ *func } };
     1010                                                newFunc->expr =
     1011                                                        referenceToRvalueConversion( newFunc->expr, newFunc->cost );
     1012                                                makeFunctionCandidates( untypedExpr->location,
     1013                                                        newFunc, function, argExpansions, found );
     1014                                        }
     1015                                } else if (
     1016                                        auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )
     1017                                ) {
     1018                                        if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) {
     1019                                                if ( auto function = clz->bound.as< ast::FunctionType >() ) {
     1020                                                        CandidateRef newFunc{ new Candidate{ *func } };
     1021                                                        newFunc->expr =
     1022                                                                referenceToRvalueConversion( newFunc->expr, newFunc->cost );
     1023                                                        makeFunctionCandidates( untypedExpr->location,
     1024                                                                newFunc, function, argExpansions, found );
     1025                                                }
     1026                                        }
     1027                                }
     1028                        } catch ( SemanticErrorException & e ) { errors.append( e ); }
     1029                }
     1030
     1031                // Find matches on function operators `?()`
     1032                if ( ! opFinder.candidates.empty() ) {
     1033                        // add exploded function alternatives to front of argument list
     1034                        std::vector< ExplodedArg > funcE;
     1035                        funcE.reserve( funcFinder.candidates.size() );
     1036                        for ( const CandidateRef & func : funcFinder ) {
     1037                                funcE.emplace_back( *func, symtab );
     1038                        }
     1039                        argExpansions.emplace_front( std::move( funcE ) );
     1040
     1041                        for ( const CandidateRef & op : opFinder ) {
     1042                                try {
     1043                                        // check if type is pointer-to-function
     1044                                        const ast::Type * opResult = op->expr->result->stripReferences();
     1045                                        if ( auto pointer = dynamic_cast< const ast::PointerType * >( opResult ) ) {
     1046                                                if ( auto function = pointer->base.as< ast::FunctionType >() ) {
     1047                                                        CandidateRef newOp{ new Candidate{ *op} };
     1048                                                        newOp->expr =
     1049                                                                referenceToRvalueConversion( newOp->expr, newOp->cost );
     1050                                                        makeFunctionCandidates( untypedExpr->location,
     1051                                                                newOp, function, argExpansions, found );
     1052                                                }
     1053                                        }
     1054                                } catch ( SemanticErrorException & e ) { errors.append( e ); }
     1055                        }
     1056                }
     1057
     1058                // Implement SFINAE; resolution errors are only errors if there aren't any non-error
     1059                // candidates
     1060                if ( found.empty() && ! errors.isEmpty() ) { throw errors; }
     1061
     1062                // Compute conversion costs
     1063                for ( CandidateRef & withFunc : found ) {
     1064                        Cost cvtCost = computeApplicationConversionCost( withFunc, symtab );
     1065
     1066                        PRINT(
     1067                                auto appExpr = withFunc->expr.strict_as< ast::ApplicationExpr >();
     1068                                auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
     1069                                auto function = pointer->base.strict_as< ast::FunctionType >();
     1070
     1071                                std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl;
     1072                                std::cerr << "parameters are:" << std::endl;
     1073                                ast::printAll( std::cerr, function->params, 2 );
     1074                                std::cerr << "arguments are:" << std::endl;
     1075                                ast::printAll( std::cerr, appExpr->args, 2 );
     1076                                std::cerr << "bindings are:" << std::endl;
     1077                                ast::print( std::cerr, withFunc->env, 2 );
     1078                                std::cerr << "cost is: " << withFunc->cost << std::endl;
     1079                                std::cerr << "cost of conversion is:" << cvtCost << std::endl;
     1080                        )
     1081
     1082                        if ( cvtCost != Cost::infinity ) {
     1083                                withFunc->cvtCost = cvtCost;
     1084                                candidates.emplace_back( std::move( withFunc ) );
     1085                        }
     1086                }
     1087                found = std::move( candidates );
     1088
     1089                // use a new list so that candidates are not examined by addAnonConversions twice
     1090                CandidateList winners = findMinCost( found );
     1091                promoteCvtCost( winners );
     1092
     1093                // function may return a struct/union value, in which case we need to add candidates
     1094                // for implicit conversions to each of the anonymous members, which must happen after
     1095                // `findMinCost`, since anon conversions are never the cheapest
     1096                for ( const CandidateRef & c : winners ) {
     1097                        addAnonConversions( c );
     1098                }
     1099                spliceBegin( candidates, winners );
     1100
     1101                if ( candidates.empty() && targetType && ! targetType->isVoid() ) {
     1102                        // If resolution is unsuccessful with a target type, try again without, since it
     1103                        // will sometimes succeed when it wouldn't with a target type binding.
     1104                        // For example:
     1105                        //   forall( otype T ) T & ?[]( T *, ptrdiff_t );
     1106                        //   const char * x = "hello world";
     1107                        //   unsigned char ch = x[0];
     1108                        // Fails with simple return type binding (xxx -- check this!) as follows:
     1109                        // * T is bound to unsigned char
     1110                        // * (x: const char *) is unified with unsigned char *, which fails
     1111                        // xxx -- fix this better
     1112                        targetType = nullptr;
     1113                        postvisit( untypedExpr );
     1114                }
     1115        }
     1116
     1117        void Finder::postvisit( const ast::AddressExpr * addressExpr ) {
     1118                CandidateFinder finder( context, tenv );
     1119                finder.find( addressExpr->arg );
     1120
     1121                if ( finder.candidates.empty() ) return;
     1122
     1123                reason.code = NoMatch;
     1124
     1125                for ( CandidateRef & r : finder.candidates ) {
     1126                        if ( ! isLvalue( r->expr ) ) continue;
     1127                        addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } );
     1128                }
     1129        }
     1130
     1131        void Finder::postvisit( const ast::LabelAddressExpr * labelExpr ) {
     1132                addCandidate( labelExpr, tenv );
     1133        }
     1134
     1135        void Finder::postvisit( const ast::CastExpr * castExpr ) {
     1136                ast::ptr< ast::Type > toType = castExpr->result;
     1137                assert( toType );
     1138                toType = resolveTypeof( toType, context );
     1139                toType = adjustExprType( toType, tenv, symtab );
     1140
     1141                CandidateFinder finder( context, tenv, toType );
     1142                finder.find( castExpr->arg, ResolvMode::withAdjustment() );
     1143
     1144                if ( !finder.candidates.empty() ) reason.code = NoMatch;
     1145
     1146                CandidateList matches;
     1147                for ( CandidateRef & cand : finder.candidates ) {
     1148                        ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
     1149                        ast::OpenVarSet open( cand->open );
     1150
     1151                        cand->env.extractOpenVars( open );
     1152
     1153                        // It is possible that a cast can throw away some values in a multiply-valued
     1154                        // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the
     1155                        // subexpression results that are cast directly. The candidate is invalid if it
     1156                        // has fewer results than there are types to cast to.
     1157                        int discardedValues = cand->expr->result->size() - toType->size();
     1158                        if ( discardedValues < 0 ) continue;
     1159
     1160                        // unification run for side-effects
     1161                        unify( toType, cand->expr->result, cand->env, need, have, open, symtab );
     1162                        Cost thisCost =
     1163                                (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast)
     1164                                        ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env )
     1165                                        : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env );
     1166
     1167                        PRINT(
     1168                                std::cerr << "working on cast with result: " << toType << std::endl;
     1169                                std::cerr << "and expr type: " << cand->expr->result << std::endl;
     1170                                std::cerr << "env: " << cand->env << std::endl;
     1171                        )
     1172                        if ( thisCost != Cost::infinity ) {
     1173                                PRINT(
     1174                                        std::cerr << "has finite cost." << std::endl;
     1175                                )
     1176                                // count one safe conversion for each value that is thrown away
     1177                                thisCost.incSafe( discardedValues );
     1178                                CandidateRef newCand = std::make_shared<Candidate>(
     1179                                        restructureCast( cand->expr, toType, castExpr->isGenerated ),
     1180                                        copy( cand->env ), std::move( open ), std::move( need ), cand->cost,
     1181                                        cand->cost + thisCost );
     1182                                inferParameters( newCand, matches );
     1183                        }
     1184                }
     1185
     1186                // select first on argument cost, then conversion cost
     1187                CandidateList minArgCost = findMinCost( matches );
     1188                promoteCvtCost( minArgCost );
     1189                candidates = findMinCost( minArgCost );
     1190        }
     1191
     1192        void Finder::postvisit( const ast::VirtualCastExpr * castExpr ) {
     1193                assertf( castExpr->result, "Implicit virtual cast targets not yet supported." );
     1194                CandidateFinder finder( context, tenv );
     1195                // don't prune here, all alternatives guaranteed to have same type
     1196                finder.find( castExpr->arg, ResolvMode::withoutPrune() );
     1197                for ( CandidateRef & r : finder.candidates ) {
     1198                        addCandidate(
     1199                                *r,
     1200                                new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );
     1201                }
     1202        }
     1203
     1204        void Finder::postvisit( const ast::KeywordCastExpr * castExpr ) {
     1205                const auto & loc = castExpr->location;
     1206                assertf( castExpr->result, "Cast target should have been set in Validate." );
     1207                auto ref = castExpr->result.strict_as<ast::ReferenceType>();
     1208                auto inst = ref->base.strict_as<ast::StructInstType>();
     1209                auto target = inst->base.get();
     1210
     1211                CandidateFinder finder( context, tenv );
     1212
     1213                auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) {
     1214                        for (auto & cand : found) {
     1215                                const ast::Type * expr = cand->expr->result.get();
     1216                                if (expect_ref) {
     1217                                        auto res = dynamic_cast<const ast::ReferenceType*>(expr);
     1218                                        if (!res) { continue; }
     1219                                        expr = res->base.get();
     1220                                }
     1221
     1222                                if (auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) {
     1223                                        auto td = cand->env.lookup(*insttype);
     1224                                        if (!td) { continue; }
     1225                                        expr = td->bound.get();
     1226                                }
     1227
     1228                                if (auto base = dynamic_cast<const ast::StructInstType*>(expr)) {
     1229                                        if (base->base == target) {
     1230                                                candidates.push_back( std::move(cand) );
     1231                                                reason.code = NoReason;
     1232                                        }
     1233                                }
     1234                        }
     1235                };
     1236
     1237                try {
     1238                        // Attempt 1 : turn (thread&)X into (thread$&)X.__thrd
     1239                        // Clone is purely for memory management
     1240                        std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) };
     1241
     1242                        // don't prune here, since it's guaranteed all alternatives will have the same type
     1243                        finder.find( tech1.get(), ResolvMode::withoutPrune() );
     1244                        pick_alternatives(finder.candidates, false);
     1245
     1246                        return;
     1247                } catch(SemanticErrorException & ) {}
     1248
     1249                // Fallback : turn (thread&)X into (thread$&)get_thread(X)
     1250                std::unique_ptr<const ast::Expr> fallback { ast::UntypedExpr::createDeref(loc,  new ast::UntypedExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.getter), { castExpr->arg })) };
     1251                // don't prune here, since it's guaranteed all alternatives will have the same type
     1252                finder.find( fallback.get(), ResolvMode::withoutPrune() );
     1253
     1254                pick_alternatives(finder.candidates, true);
     1255
     1256                // Whatever happens here, we have no more fallbacks
     1257        }
     1258
     1259        void Finder::postvisit( const ast::UntypedMemberExpr * memberExpr ) {
     1260                CandidateFinder aggFinder( context, tenv );
     1261                aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() );
     1262                for ( CandidateRef & agg : aggFinder.candidates ) {
     1263                        // it's okay for the aggregate expression to have reference type -- cast it to the
     1264                        // base type to treat the aggregate as the referenced value
     1265                        Cost addedCost = Cost::zero;
     1266                        agg->expr = referenceToRvalueConversion( agg->expr, addedCost );
     1267
     1268                        // find member of the given type
     1269                        if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) {
     1270                                addAggMembers(
     1271                                        structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
     1272                        } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) {
     1273                                addAggMembers(
     1274                                        unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
     1275                        } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) {
     1276                                addTupleMembers( tupleType, agg->expr, *agg, addedCost, memberExpr->member );
     1277                        }
     1278                }
     1279        }
     1280
     1281        void Finder::postvisit( const ast::MemberExpr * memberExpr ) {
     1282                addCandidate( memberExpr, tenv );
     1283        }
     1284
     1285        void Finder::postvisit( const ast::NameExpr * nameExpr ) {
     1286                std::vector< ast::SymbolTable::IdData > declList;
     1287                if (!selfFinder.otypeKeys.empty()) {
     1288                        auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
     1289                        assertf(kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS, "special lookup with non-special target: %s", nameExpr->name.c_str());
     1290
     1291                        for (auto & otypeKey: selfFinder.otypeKeys) {
     1292                                auto result = symtab.specialLookupId(kind, otypeKey);
     1293                                declList.insert(declList.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end()));
     1294                        }
     1295                } else {
     1296                        declList = symtab.lookupId( nameExpr->name );
     1297                }
     1298                PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
     1299
     1300                if ( declList.empty() ) return;
     1301
     1302                reason.code = NoMatch;
     1303
     1304                for ( auto & data : declList ) {
     1305                        Cost cost = Cost::zero;
     1306                        ast::Expr * newExpr = data.combine( nameExpr->location, cost );
     1307
     1308                        CandidateRef newCand = std::make_shared<Candidate>(
     1309                                newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
     1310                                cost );
     1311
     1312                        if (newCand->expr->env) {
     1313                                newCand->env.add(*newCand->expr->env);
     1314                                auto mutExpr = newCand->expr.get_and_mutate();
     1315                                mutExpr->env  = nullptr;
     1316                                newCand->expr = mutExpr;
     1317                        }
     1318
     1319                        PRINT(
     1320                                std::cerr << "decl is ";
     1321                                ast::print( std::cerr, data.id );
     1322                                std::cerr << std::endl;
     1323                                std::cerr << "newExpr is ";
     1324                                ast::print( std::cerr, newExpr );
     1325                                std::cerr << std::endl;
     1326                        )
     1327                        newCand->expr = ast::mutate_field(
     1328                                newCand->expr.get(), &ast::Expr::result,
     1329                                renameTyVars( newCand->expr->result ) );
     1330                        // add anonymous member interpretations whenever an aggregate value type is seen
     1331                        // as a name expression
     1332                        addAnonConversions( newCand );
     1333                        candidates.emplace_back( std::move( newCand ) );
     1334                }
     1335        }
     1336
     1337        void Finder::postvisit( const ast::VariableExpr * variableExpr ) {
     1338                // not sufficient to just pass `variableExpr` here, type might have changed since
     1339                // creation
     1340                addCandidate(
     1341                        new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv );
     1342        }
     1343
     1344        void Finder::postvisit( const ast::ConstantExpr * constantExpr ) {
     1345                addCandidate( constantExpr, tenv );
     1346        }
     1347
     1348        void Finder::postvisit( const ast::SizeofExpr * sizeofExpr ) {
     1349                if ( sizeofExpr->type ) {
     1350                        addCandidate(
     1351                                new ast::SizeofExpr{
     1352                                        sizeofExpr->location, resolveTypeof( sizeofExpr->type, context ) },
     1353                                tenv );
     1354                } else {
     1355                        // find all candidates for the argument to sizeof
     1356                        CandidateFinder finder( context, tenv );
     1357                        finder.find( sizeofExpr->expr );
     1358                        // find the lowest-cost candidate, otherwise ambiguous
     1359                        CandidateList winners = findMinCost( finder.candidates );
     1360                        if ( winners.size() != 1 ) {
     1361                                SemanticError(
     1362                                        sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " );
     1363                        }
     1364                        // return the lowest-cost candidate
     1365                        CandidateRef & choice = winners.front();
     1366                        choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
     1367                        choice->cost = Cost::zero;
     1368                        addCandidate( *choice, new ast::SizeofExpr{ sizeofExpr->location, choice->expr } );
     1369                }
     1370        }
     1371
     1372        void Finder::postvisit( const ast::AlignofExpr * alignofExpr ) {
     1373                if ( alignofExpr->type ) {
     1374                        addCandidate(
     1375                                new ast::AlignofExpr{
     1376                                        alignofExpr->location, resolveTypeof( alignofExpr->type, context ) },
     1377                                tenv );
     1378                } else {
     1379                        // find all candidates for the argument to alignof
     1380                        CandidateFinder finder( context, tenv );
     1381                        finder.find( alignofExpr->expr );
     1382                        // find the lowest-cost candidate, otherwise ambiguous
     1383                        CandidateList winners = findMinCost( finder.candidates );
     1384                        if ( winners.size() != 1 ) {
     1385                                SemanticError(
     1386                                        alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " );
     1387                        }
     1388                        // return the lowest-cost candidate
     1389                        CandidateRef & choice = winners.front();
     1390                        choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
     1391                        choice->cost = Cost::zero;
     1392                        addCandidate(
     1393                                *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } );
     1394                }
     1395        }
     1396
     1397        void Finder::postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) {
     1398                const ast::BaseInstType * aggInst;
     1399                if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ;
     1400                else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ;
     1401                else return;
     1402
     1403                for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) {
     1404                        auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member );
     1405                        addCandidate(
     1406                                new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv );
     1407                }
     1408        }
     1409
     1410        void Finder::postvisit( const ast::OffsetofExpr * offsetofExpr ) {
     1411                addCandidate( offsetofExpr, tenv );
     1412        }
     1413
     1414        void Finder::postvisit( const ast::OffsetPackExpr * offsetPackExpr ) {
     1415                addCandidate( offsetPackExpr, tenv );
     1416        }
     1417
     1418        void Finder::postvisit( const ast::LogicalExpr * logicalExpr ) {
     1419                CandidateFinder finder1( context, tenv );
     1420                finder1.find( logicalExpr->arg1, ResolvMode::withAdjustment() );
     1421                if ( finder1.candidates.empty() ) return;
     1422
     1423                CandidateFinder finder2( context, tenv );
     1424                finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() );
     1425                if ( finder2.candidates.empty() ) return;
     1426
     1427                reason.code = NoMatch;
     1428
     1429                for ( const CandidateRef & r1 : finder1.candidates ) {
     1430                        for ( const CandidateRef & r2 : finder2.candidates ) {
     1431                                ast::TypeEnvironment env{ r1->env };
     1432                                env.simpleCombine( r2->env );
     1433                                ast::OpenVarSet open{ r1->open };
     1434                                mergeOpenVars( open, r2->open );
     1435                                ast::AssertionSet need;
     1436                                mergeAssertionSet( need, r1->need );
     1437                                mergeAssertionSet( need, r2->need );
     1438
     1439                                addCandidate(
     1440                                        new ast::LogicalExpr{
     1441                                                logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd },
     1442                                        std::move( env ), std::move( open ), std::move( need ), r1->cost + r2->cost );
     1443                        }
     1444                }
     1445        }
     1446
     1447        void Finder::postvisit( const ast::ConditionalExpr * conditionalExpr ) {
     1448                // candidates for condition
     1449                CandidateFinder finder1( context, tenv );
     1450                finder1.find( conditionalExpr->arg1, ResolvMode::withAdjustment() );
     1451                if ( finder1.candidates.empty() ) return;
     1452
     1453                // candidates for true result
     1454                CandidateFinder finder2( context, tenv );
     1455                finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() );
     1456                if ( finder2.candidates.empty() ) return;
     1457
     1458                // candidates for false result
     1459                CandidateFinder finder3( context, tenv );
     1460                finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );
     1461                if ( finder3.candidates.empty() ) return;
     1462
     1463                reason.code = NoMatch;
     1464
     1465                for ( const CandidateRef & r1 : finder1.candidates ) {
     1466                        for ( const CandidateRef & r2 : finder2.candidates ) {
     1467                                for ( const CandidateRef & r3 : finder3.candidates ) {
     1468                                        ast::TypeEnvironment env{ r1->env };
     1469                                        env.simpleCombine( r2->env );
     1470                                        env.simpleCombine( r3->env );
     1471                                        ast::OpenVarSet open{ r1->open };
     1472                                        mergeOpenVars( open, r2->open );
     1473                                        mergeOpenVars( open, r3->open );
     1474                                        ast::AssertionSet need;
     1475                                        mergeAssertionSet( need, r1->need );
     1476                                        mergeAssertionSet( need, r2->need );
     1477                                        mergeAssertionSet( need, r3->need );
     1478                                        ast::AssertionSet have;
     1479
     1480                                        // unify true and false results, then infer parameters to produce new
     1481                                        // candidates
     1482                                        ast::ptr< ast::Type > common;
     1483                                        if (
     1484                                                unify(
     1485                                                        r2->expr->result, r3->expr->result, env, need, have, open, symtab,
     1486                                                        common )
     1487                                        ) {
     1488                                                // generate typed expression
     1489                                                ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{
     1490                                                        conditionalExpr->location, r1->expr, r2->expr, r3->expr };
     1491                                                newExpr->result = common ? common : r2->expr->result;
     1492                                                // convert both options to result type
     1493                                                Cost cost = r1->cost + r2->cost + r3->cost;
     1494                                                newExpr->arg2 = computeExpressionConversionCost(
     1495                                                        newExpr->arg2, newExpr->result, symtab, env, cost );
     1496                                                newExpr->arg3 = computeExpressionConversionCost(
     1497                                                        newExpr->arg3, newExpr->result, symtab, env, cost );
     1498                                                // output candidate
     1499                                                CandidateRef newCand = std::make_shared<Candidate>(
     1500                                                        newExpr, std::move( env ), std::move( open ), std::move( need ), cost );
     1501                                                inferParameters( newCand, candidates );
     1502                                        }
     1503                                }
     1504                        }
     1505                }
     1506        }
     1507
     1508        void Finder::postvisit( const ast::CommaExpr * commaExpr ) {
     1509                ast::TypeEnvironment env{ tenv };
     1510                ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, context, env );
     1511
     1512                CandidateFinder finder2( context, env );
     1513                finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() );
     1514
     1515                for ( const CandidateRef & r2 : finder2.candidates ) {
     1516                        addCandidate( *r2, new ast::CommaExpr{ commaExpr->location, arg1, r2->expr } );
     1517                }
     1518        }
     1519
     1520        void Finder::postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ) {
     1521                addCandidate( ctorExpr, tenv );
     1522        }
     1523
     1524        void Finder::postvisit( const ast::ConstructorExpr * ctorExpr ) {
     1525                CandidateFinder finder( context, tenv );
     1526                finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() );
     1527                for ( CandidateRef & r : finder.candidates ) {
     1528                        addCandidate( *r, new ast::ConstructorExpr{ ctorExpr->location, r->expr } );
     1529                }
     1530        }
     1531
     1532        void Finder::postvisit( const ast::RangeExpr * rangeExpr ) {
     1533                // resolve low and high, accept candidates where low and high types unify
     1534                CandidateFinder finder1( context, tenv );
     1535                finder1.find( rangeExpr->low, ResolvMode::withAdjustment() );
     1536                if ( finder1.candidates.empty() ) return;
     1537
     1538                CandidateFinder finder2( context, tenv );
     1539                finder2.find( rangeExpr->high, ResolvMode::withAdjustment() );
     1540                if ( finder2.candidates.empty() ) return;
     1541
     1542                reason.code = NoMatch;
     1543
     1544                for ( const CandidateRef & r1 : finder1.candidates ) {
     1545                        for ( const CandidateRef & r2 : finder2.candidates ) {
     1546                                ast::TypeEnvironment env{ r1->env };
     1547                                env.simpleCombine( r2->env );
     1548                                ast::OpenVarSet open{ r1->open };
     1549                                mergeOpenVars( open, r2->open );
     1550                                ast::AssertionSet need;
     1551                                mergeAssertionSet( need, r1->need );
     1552                                mergeAssertionSet( need, r2->need );
     1553                                ast::AssertionSet have;
     1554
     1555                                ast::ptr< ast::Type > common;
     1556                                if (
     1557                                        unify(
     1558                                                r1->expr->result, r2->expr->result, env, need, have, open, symtab,
     1559                                                common )
     1560                                ) {
     1561                                        // generate new expression
     1562                                        ast::RangeExpr * newExpr =
     1563                                                new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };
     1564                                        newExpr->result = common ? common : r1->expr->result;
     1565                                        // add candidate
     1566                                        CandidateRef newCand = std::make_shared<Candidate>(
     1567                                                newExpr, std::move( env ), std::move( open ), std::move( need ),
     1568                                                r1->cost + r2->cost );
     1569                                        inferParameters( newCand, candidates );
     1570                                }
     1571                        }
     1572                }
     1573        }
     1574
     1575        void Finder::postvisit( const ast::UntypedTupleExpr * tupleExpr ) {
     1576                std::vector< CandidateFinder > subCandidates =
     1577                        selfFinder.findSubExprs( tupleExpr->exprs );
     1578                std::vector< CandidateList > possibilities;
     1579                combos( subCandidates.begin(), subCandidates.end(), back_inserter( possibilities ) );
     1580
     1581                for ( const CandidateList & subs : possibilities ) {
     1582                        std::vector< ast::ptr< ast::Expr > > exprs;
     1583                        exprs.reserve( subs.size() );
     1584                        for ( const CandidateRef & sub : subs ) { exprs.emplace_back( sub->expr ); }
     1585
     1586                        ast::TypeEnvironment env;
     1587                        ast::OpenVarSet open;
     1588                        ast::AssertionSet need;
     1589                        for ( const CandidateRef & sub : subs ) {
     1590                                env.simpleCombine( sub->env );
     1591                                mergeOpenVars( open, sub->open );
     1592                                mergeAssertionSet( need, sub->need );
     1593                        }
     1594
     1595                        addCandidate(
     1596                                new ast::TupleExpr{ tupleExpr->location, std::move( exprs ) },
     1597                                std::move( env ), std::move( open ), std::move( need ), sumCost( subs ) );
     1598                }
     1599        }
     1600
     1601        void Finder::postvisit( const ast::TupleExpr * tupleExpr ) {
     1602                addCandidate( tupleExpr, tenv );
     1603        }
     1604
     1605        void Finder::postvisit( const ast::TupleIndexExpr * tupleExpr ) {
     1606                addCandidate( tupleExpr, tenv );
     1607        }
     1608
     1609        void Finder::postvisit( const ast::TupleAssignExpr * tupleExpr ) {
     1610                addCandidate( tupleExpr, tenv );
     1611        }
     1612
     1613        void Finder::postvisit( const ast::UniqueExpr * unqExpr ) {
     1614                CandidateFinder finder( context, tenv );
     1615                finder.find( unqExpr->expr, ResolvMode::withAdjustment() );
     1616                for ( CandidateRef & r : finder.candidates ) {
     1617                        // ensure that the the id is passed on so that the expressions are "linked"
     1618                        addCandidate( *r, new ast::UniqueExpr{ unqExpr->location, r->expr, unqExpr->id } );
     1619                }
     1620        }
     1621
     1622        void Finder::postvisit( const ast::StmtExpr * stmtExpr ) {
     1623                addCandidate( resolveStmtExpr( stmtExpr, context ), tenv );
     1624        }
     1625
     1626        void Finder::postvisit( const ast::UntypedInitExpr * initExpr ) {
     1627                // handle each option like a cast
     1628                CandidateList matches;
     1629                PRINT(
     1630                        std::cerr << "untyped init expr: " << initExpr << std::endl;
     1631                )
     1632                // O(n^2) checks of d-types with e-types
     1633                for ( const ast::InitAlternative & initAlt : initExpr->initAlts ) {
     1634                        // calculate target type
     1635                        const ast::Type * toType = resolveTypeof( initAlt.type, context );
     1636                        toType = adjustExprType( toType, tenv, symtab );
     1637                        // The call to find must occur inside this loop, otherwise polymorphic return
     1638                        // types are not bound to the initialization type, since return type variables are
     1639                        // only open for the duration of resolving the UntypedExpr.
     1640                        CandidateFinder finder( context, tenv, toType );
     1641                        finder.find( initExpr->expr, ResolvMode::withAdjustment() );
     1642                        for ( CandidateRef & cand : finder.candidates ) {
     1643                                if (reason.code == NotFound) reason.code = NoMatch;
     1644
     1645                                ast::TypeEnvironment env{ cand->env };
     1646                                ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
     1647                                ast::OpenVarSet open{ cand->open };
     1648
     1649                                PRINT(
     1650                                        std::cerr << "  @ " << toType << " " << initAlt.designation << std::endl;
     1651                                )
     1652
     1653                                // It is possible that a cast can throw away some values in a multiply-valued
     1654                                // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of
     1655                                // the subexpression results that are cast directly. The candidate is invalid
     1656                                // if it has fewer results than there are types to cast to.
     1657                                int discardedValues = cand->expr->result->size() - toType->size();
     1658                                if ( discardedValues < 0 ) continue;
     1659
     1660                                // unification run for side-effects
     1661                                bool canUnify = unify( toType, cand->expr->result, env, need, have, open, symtab );
     1662                                (void) canUnify;
     1663                                Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(),
     1664                                        symtab, env );
     1665                                PRINT(
     1666                                        Cost legacyCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(),
     1667                                                symtab, env );
     1668                                        std::cerr << "Considering initialization:";
     1669                                        std::cerr << std::endl << "  FROM: " << cand->expr->result << std::endl;
     1670                                        std::cerr << std::endl << "  TO: "   << toType             << std::endl;
     1671                                        std::cerr << std::endl << "  Unification " << (canUnify ? "succeeded" : "failed");
     1672                                        std::cerr << std::endl << "  Legacy cost " << legacyCost;
     1673                                        std::cerr << std::endl << "  New cost " << thisCost;
     1674                                        std::cerr << std::endl;
     1675                                )
     1676                                if ( thisCost != Cost::infinity ) {
     1677                                        // count one safe conversion for each value that is thrown away
     1678                                        thisCost.incSafe( discardedValues );
     1679                                        CandidateRef newCand = std::make_shared<Candidate>(
     1680                                                new ast::InitExpr{
     1681                                                        initExpr->location, restructureCast( cand->expr, toType ),
     1682                                                        initAlt.designation },
     1683                                                std::move(env), std::move( open ), std::move( need ), cand->cost, thisCost );
     1684                                        inferParameters( newCand, matches );
     1685                                }
     1686                        }
     1687                }
     1688
     1689                // select first on argument cost, then conversion cost
     1690                CandidateList minArgCost = findMinCost( matches );
     1691                promoteCvtCost( minArgCost );
     1692                candidates = findMinCost( minArgCost );
     1693        }
     1694
     1695        // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder");
     1696        /// Prunes a list of candidates down to those that have the minimum conversion cost for a given
     1697        /// return type. Skips ambiguous candidates.
     1698
     1699} // anonymous namespace
     1700
     1701bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) {
     1702        struct PruneStruct {
     1703                CandidateRef candidate;
     1704                bool ambiguous;
     1705
     1706                PruneStruct() = default;
     1707                PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {}
     1708        };
     1709
     1710        // find lowest-cost candidate for each type
     1711        std::unordered_map< std::string, PruneStruct > selected;
     1712        // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found
     1713        std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;});
     1714        for ( CandidateRef & candidate : candidates ) {
     1715                std::string mangleName;
     1716                {
     1717                        ast::ptr< ast::Type > newType = candidate->expr->result;
     1718                        assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get());
     1719                        candidate->env.apply( newType );
     1720                        mangleName = Mangle::mangle( newType );
     1721                }
     1722
     1723                auto found = selected.find( mangleName );
     1724                if (found != selected.end() && found->second.candidate->cost < candidate->cost) {
     1725                        PRINT(
     1726                                std::cerr << "cost " << candidate->cost << " loses to "
     1727                                        << found->second.candidate->cost << std::endl;
     1728                        )
     1729                        continue;
     1730                }
     1731
     1732                // xxx - when do satisfyAssertions produce more than 1 result?
     1733                // this should only happen when initial result type contains
     1734                // unbound type parameters, then it should never be pruned by
     1735                // the previous step, since renameTyVars guarantees the mangled name
     1736                // is unique.
     1737                CandidateList satisfied;
     1738                bool needRecomputeKey = false;
     1739                if (candidate->need.empty()) {
     1740                        satisfied.emplace_back(candidate);
     1741                }
     1742                else {
     1743                        satisfyAssertions(candidate, context.symtab, satisfied, errors);
     1744                        needRecomputeKey = true;
     1745                }
     1746
     1747                for (auto & newCand : satisfied) {
     1748                        // recomputes type key, if satisfyAssertions changed it
     1749                        if (needRecomputeKey)
     1750                        {
     1751                                ast::ptr< ast::Type > newType = newCand->expr->result;
     1752                                assertf(newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get());
     1753                                newCand->env.apply( newType );
     1754                                mangleName = Mangle::mangle( newType );
     1755                        }
     1756                        auto found = selected.find( mangleName );
     1757                        if ( found != selected.end() ) {
     1758                                if ( newCand->cost < found->second.candidate->cost ) {
     1759                                        PRINT(
     1760                                                std::cerr << "cost " << newCand->cost << " beats "
     1761                                                        << found->second.candidate->cost << std::endl;
     1762                                        )
     1763
     1764                                        found->second = PruneStruct{ newCand };
     1765                                } else if ( newCand->cost == found->second.candidate->cost ) {
     1766                                        // if one of the candidates contains a deleted identifier, can pick the other,
     1767                                        // since deleted expressions should not be ambiguous if there is another option
     1768                                        // that is at least as good
     1769                                        if ( findDeletedExpr( newCand->expr ) ) {
     1770                                                // do nothing
     1771                                                PRINT( std::cerr << "candidate is deleted" << std::endl; )
     1772                                        } else if ( findDeletedExpr( found->second.candidate->expr ) ) {
     1773                                                PRINT( std::cerr << "current is deleted" << std::endl; )
     1774                                                found->second = PruneStruct{ newCand };
     1775                                        } else {
     1776                                                PRINT( std::cerr << "marking ambiguous" << std::endl; )
     1777                                                found->second.ambiguous = true;
     1778                                        }
     1779                                } else {
     1780                                        // xxx - can satisfyAssertions increase the cost?
     1781                                        PRINT(
     1782                                                std::cerr << "cost " << newCand->cost << " loses to "
     1783                                                        << found->second.candidate->cost << std::endl;
     1784                                        )
     1785                                }
     1786                        } else {
     1787                                selected.emplace_hint( found, mangleName, newCand );
     1788                        }
     1789                }
     1790        }
     1791
     1792        // report unambiguous min-cost candidates
     1793        // CandidateList out;
     1794        for ( auto & target : selected ) {
     1795                if ( target.second.ambiguous ) continue;
     1796
     1797                CandidateRef cand = target.second.candidate;
     1798
     1799                ast::ptr< ast::Type > newResult = cand->expr->result;
     1800                cand->env.applyFree( newResult );
     1801                cand->expr = ast::mutate_field(
     1802                        cand->expr.get(), &ast::Expr::result, std::move( newResult ) );
     1803
     1804                out.emplace_back( cand );
     1805        }
     1806        // if everything is lost in satisfyAssertions, report the error
     1807        return !selected.empty();
     1808}
     1809
     1810void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) {
     1811        // Find alternatives for expression
     1812        ast::Pass<Finder> finder{ *this };
     1813        expr->accept( finder );
     1814
     1815        if ( mode.failFast && candidates.empty() ) {
     1816                switch(finder.core.reason.code) {
     1817                case Finder::NotFound:
     1818                        { SemanticError( expr, "No alternatives for expression " ); break; }
     1819                case Finder::NoMatch:
     1820                        { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; }
     1821                case Finder::ArgsToFew:
     1822                case Finder::ArgsToMany:
     1823                case Finder::RetsToFew:
     1824                case Finder::RetsToMany:
     1825                case Finder::NoReason:
     1826                default:
     1827                        { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); }
     1828                }
     1829        }
     1830
     1831        /*
     1832        if ( mode.satisfyAssns || mode.prune ) {
     1833                // trim candidates to just those where the assertions are satisfiable
     1834                // - necessary pre-requisite to pruning
     1835                CandidateList satisfied;
     1836                std::vector< std::string > errors;
     1837                for ( CandidateRef & candidate : candidates ) {
     1838                        satisfyAssertions( candidate, localSyms, satisfied, errors );
     1839                }
     1840
     1841                // fail early if none such
     1842                if ( mode.failFast && satisfied.empty() ) {
     1843                        std::ostringstream stream;
     1844                        stream << "No alternatives with satisfiable assertions for " << expr << "\n";
     1845                        for ( const auto& err : errors ) {
     1846                                stream << err;
     1847                        }
     1848                        SemanticError( expr->location, stream.str() );
     1849                }
     1850
     1851                // reset candidates
     1852                candidates = move( satisfied );
     1853        }
     1854        */
     1855
     1856        if ( mode.prune ) {
     1857                // trim candidates to single best one
     1858                PRINT(
     1859                        std::cerr << "alternatives before prune:" << std::endl;
     1860                        print( std::cerr, candidates );
     1861                )
     1862
     1863                CandidateList pruned;
     1864                std::vector<std::string> errors;
     1865                bool found = pruneCandidates( candidates, pruned, errors );
     1866
     1867                if ( mode.failFast && pruned.empty() ) {
     1868                        std::ostringstream stream;
     1869                        if (found) {
     1870                                CandidateList winners = findMinCost( candidates );
     1871                                stream << "Cannot choose between " << winners.size() << " alternatives for "
     1872                                        "expression\n";
     1873                                ast::print( stream, expr );
     1874                                stream << " Alternatives are:\n";
     1875                                print( stream, winners, 1 );
     1876                                SemanticError( expr->location, stream.str() );
     1877                        }
     1878                        else {
     1879                                stream << "No alternatives with satisfiable assertions for " << expr << "\n";
     1880                                for ( const auto& err : errors ) {
     1881                                        stream << err;
     1882                                }
     1883                                SemanticError( expr->location, stream.str() );
     1884                        }
     1885                }
     1886
     1887                auto oldsize = candidates.size();
     1888                candidates = std::move( pruned );
     1889
     1890                PRINT(
     1891                        std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl;
     1892                )
     1893                PRINT(
     1894                        std::cerr << "there are " << candidates.size() << " alternatives after elimination"
     1895                                << std::endl;
     1896                )
     1897        }
     1898
     1899        // adjust types after pruning so that types substituted by pruneAlternatives are correctly
     1900        // adjusted
     1901        if ( mode.adjust ) {
     1902                for ( CandidateRef & r : candidates ) {
     1903                        r->expr = ast::mutate_field(
     1904                                r->expr.get(), &ast::Expr::result,
     1905                                adjustExprType( r->expr->result, r->env, context.symtab ) );
     1906                }
     1907        }
     1908
     1909        // Central location to handle gcc extension keyword, etc. for all expressions
     1910        for ( CandidateRef & r : candidates ) {
     1911                if ( r->expr->extension != expr->extension ) {
     1912                        r->expr.get_and_mutate()->extension = expr->extension;
     1913                }
     1914        }
     1915}
     1916
     1917std::vector< CandidateFinder > CandidateFinder::findSubExprs(
     1918        const std::vector< ast::ptr< ast::Expr > > & xs
     1919) {
     1920        std::vector< CandidateFinder > out;
     1921
     1922        for ( const auto & x : xs ) {
     1923                out.emplace_back( context, env );
     1924                out.back().find( x, ResolvMode::withAdjustment() );
     1925
     1926                PRINT(
     1927                        std::cerr << "findSubExprs" << std::endl;
     1928                        print( std::cerr, out.back().candidates );
     1929                )
     1930        }
     1931
     1932        return out;
     1933}
     1934
    571935const ast::Expr * referenceToRvalueConversion( const ast::Expr * expr, Cost & cost ) {
    581936        if ( expr->result.as< ast::ReferenceType >() ) {
     
    641942        return expr;
    651943}
    66 
    67 /// Unique identifier for matching expression resolutions to their requesting expression
    68 UniqueId globalResnSlot = 0;
    691944
    701945Cost computeConversionCost(
     
    931968}
    941969
    95 namespace {
    96         /// First index is which argument, second is which alternative, third is which exploded element
    97         using ExplodedArgs_new = std::deque< std::vector< ExplodedArg > >;
    98 
    99         /// Returns a list of alternatives with the minimum cost in the given list
    100         CandidateList findMinCost( const CandidateList & candidates ) {
    101                 CandidateList out;
    102                 Cost minCost = Cost::infinity;
    103                 for ( const CandidateRef & r : candidates ) {
    104                         if ( r->cost < minCost ) {
    105                                 minCost = r->cost;
    106                                 out.clear();
    107                                 out.emplace_back( r );
    108                         } else if ( r->cost == minCost ) {
    109                                 out.emplace_back( r );
    110                         }
    111                 }
    112                 return out;
    113         }
    114 
    115         /// Computes conversion cost for a given expression to a given type
    116         const ast::Expr * computeExpressionConversionCost(
    117                 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost
    118         ) {
    119                 Cost convCost = computeConversionCost(
    120                                 arg->result, paramType, arg->get_lvalue(), symtab, env );
    121                 outCost += convCost;
    122 
    123                 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires
    124                 // conversion. Ignore poly cost for now, since this requires resolution of the cast to
    125                 // infer parameters and this does not currently work for the reason stated below
    126                 Cost tmpCost = convCost;
    127                 tmpCost.incPoly( -tmpCost.get_polyCost() );
    128                 if ( tmpCost != Cost::zero ) {
    129                         ast::ptr< ast::Type > newType = paramType;
    130                         env.apply( newType );
    131                         return new ast::CastExpr{ arg, newType };
    132 
    133                         // xxx - *should* be able to resolve this cast, but at the moment pointers are not
    134                         // castable to zero_t, but are implicitly convertible. This is clearly inconsistent,
    135                         // once this is fixed it should be possible to resolve the cast.
    136                         // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable,
    137                         // but it shouldn't be because this makes the conversion from DT* to DT* since
    138                         // commontype(zero_t, DT*) is DT*, rather than nothing
    139 
    140                         // CandidateFinder finder{ symtab, env };
    141                         // finder.find( arg, ResolvMode::withAdjustment() );
    142                         // assertf( finder.candidates.size() > 0,
    143                         //      "Somehow castable expression failed to find alternatives." );
    144                         // assertf( finder.candidates.size() == 1,
    145                         //      "Somehow got multiple alternatives for known cast expression." );
    146                         // return finder.candidates.front()->expr;
    147                 }
    148 
    149                 return arg;
    150         }
    151 
    152         /// Computes conversion cost for a given candidate
    153         Cost computeApplicationConversionCost(
    154                 CandidateRef cand, const ast::SymbolTable & symtab
    155         ) {
    156                 auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >();
    157                 auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
    158                 auto function = pointer->base.strict_as< ast::FunctionType >();
    159 
    160                 Cost convCost = Cost::zero;
    161                 const auto & params = function->params;
    162                 auto param = params.begin();
    163                 auto & args = appExpr->args;
    164 
    165                 for ( unsigned i = 0; i < args.size(); ++i ) {
    166                         const ast::Type * argType = args[i]->result;
    167                         PRINT(
    168                                 std::cerr << "arg expression:" << std::endl;
    169                                 ast::print( std::cerr, args[i], 2 );
    170                                 std::cerr << "--- results are" << std::endl;
    171                                 ast::print( std::cerr, argType, 2 );
    172                         )
    173 
    174                         if ( param == params.end() ) {
    175                                 if ( function->isVarArgs ) {
    176                                         convCost.incUnsafe();
    177                                         PRINT( std::cerr << "end of params with varargs function: inc unsafe: "
    178                                                 << convCost << std::endl; ; )
    179                                         // convert reference-typed expressions into value-typed expressions
    180                                         cand->expr = ast::mutate_field_index(
    181                                                 appExpr, &ast::ApplicationExpr::args, i,
    182                                                 referenceToRvalueConversion( args[i], convCost ) );
    183                                         continue;
    184                                 } else return Cost::infinity;
    185                         }
    186 
    187                         if ( auto def = args[i].as< ast::DefaultArgExpr >() ) {
    188                                 // Default arguments should be free - don't include conversion cost.
    189                                 // Unwrap them here because they are not relevant to the rest of the system
    190                                 cand->expr = ast::mutate_field_index(
    191                                         appExpr, &ast::ApplicationExpr::args, i, def->expr );
    192                                 ++param;
    193                                 continue;
    194                         }
    195 
    196                         // mark conversion cost and also specialization cost of param type
    197                         // const ast::Type * paramType = (*param)->get_type();
    198                         cand->expr = ast::mutate_field_index(
    199                                 appExpr, &ast::ApplicationExpr::args, i,
    200                                 computeExpressionConversionCost(
    201                                         args[i], *param, symtab, cand->env, convCost ) );
    202                         convCost.decSpec( specCost( *param ) );
    203                         ++param;  // can't be in for-loop update because of the continue
    204                 }
    205 
    206                 if ( param != params.end() ) return Cost::infinity;
    207 
    208                 // specialization cost of return types can't be accounted for directly, it disables
    209                 // otherwise-identical calls, like this example based on auto-newline in the I/O lib:
    210                 //
    211                 //   forall(otype OS) {
    212                 //     void ?|?(OS&, int);  // with newline
    213                 //     OS&  ?|?(OS&, int);  // no newline, always chosen due to more specialization
    214                 //   }
    215 
    216                 // mark type variable and specialization cost of forall clause
    217                 convCost.incVar( function->forall.size() );
    218                 convCost.decSpec( function->assertions.size() );
    219 
    220                 return convCost;
    221         }
    222 
    223         void makeUnifiableVars(
    224                 const ast::FunctionType * type, ast::OpenVarSet & unifiableVars,
    225                 ast::AssertionSet & need
    226         ) {
    227                 for ( auto & tyvar : type->forall ) {
    228                         unifiableVars[ *tyvar ] = ast::TypeData{ tyvar->base };
    229                 }
    230                 for ( auto & assn : type->assertions ) {
    231                         need[ assn ].isUsed = true;
    232                 }
    233         }
    234 
    235         /// Gets a default value from an initializer, nullptr if not present
    236         const ast::ConstantExpr * getDefaultValue( const ast::Init * init ) {
    237                 if ( auto si = dynamic_cast< const ast::SingleInit * >( init ) ) {
    238                         if ( auto ce = si->value.as< ast::CastExpr >() ) {
    239                                 return ce->arg.as< ast::ConstantExpr >();
    240                         } else {
    241                                 return si->value.as< ast::ConstantExpr >();
    242                         }
    243                 }
    244                 return nullptr;
    245         }
    246 
    247         /// State to iteratively build a match of parameter expressions to arguments
    248         struct ArgPack {
    249                 std::size_t parent;          ///< Index of parent pack
    250                 ast::ptr< ast::Expr > expr;  ///< The argument stored here
    251                 Cost cost;                   ///< The cost of this argument
    252                 ast::TypeEnvironment env;    ///< Environment for this pack
    253                 ast::AssertionSet need;      ///< Assertions outstanding for this pack
    254                 ast::AssertionSet have;      ///< Assertions found for this pack
    255                 ast::OpenVarSet open;        ///< Open variables for this pack
    256                 unsigned nextArg;            ///< Index of next argument in arguments list
    257                 unsigned tupleStart;         ///< Number of tuples that start at this index
    258                 unsigned nextExpl;           ///< Index of next exploded element
    259                 unsigned explAlt;            ///< Index of alternative for nextExpl > 0
    260 
    261                 ArgPack()
    262                 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ),
    263                   tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
    264 
    265                 ArgPack(
    266                         const ast::TypeEnvironment & env, const ast::AssertionSet & need,
    267                         const ast::AssertionSet & have, const ast::OpenVarSet & open )
    268                 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),
    269                   open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
    270 
    271                 ArgPack(
    272                         std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,
    273                         ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,
    274                         unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,
    275                         unsigned nextExpl = 0, unsigned explAlt = 0 )
    276                 : parent(parent), expr( expr ), cost( cost ), env( std::move( env ) ), need( std::move( need ) ),
    277                   have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),
    278                   nextExpl( nextExpl ), explAlt( explAlt ) {}
    279 
    280                 ArgPack(
    281                         const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need,
    282                         ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added )
    283                 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( std::move( env ) ),
    284                   need( std::move( need ) ), have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ),
    285                   tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {}
    286 
    287                 /// true if this pack is in the middle of an exploded argument
    288                 bool hasExpl() const { return nextExpl > 0; }
    289 
    290                 /// Gets the list of exploded candidates for this pack
    291                 const ExplodedArg & getExpl( const ExplodedArgs_new & args ) const {
    292                         return args[ nextArg-1 ][ explAlt ];
    293                 }
    294 
    295                 /// Ends a tuple expression, consolidating the appropriate args
    296                 void endTuple( const std::vector< ArgPack > & packs ) {
    297                         // add all expressions in tuple to list, summing cost
    298                         std::deque< const ast::Expr * > exprs;
    299                         const ArgPack * pack = this;
    300                         if ( expr ) { exprs.emplace_front( expr ); }
    301                         while ( pack->tupleStart == 0 ) {
    302                                 pack = &packs[pack->parent];
    303                                 exprs.emplace_front( pack->expr );
    304                                 cost += pack->cost;
    305                         }
    306                         // reset pack to appropriate tuple
    307                         std::vector< ast::ptr< ast::Expr > > exprv( exprs.begin(), exprs.end() );
    308                         expr = new ast::TupleExpr{ expr->location, std::move( exprv ) };
    309                         tupleStart = pack->tupleStart - 1;
    310                         parent = pack->parent;
    311                 }
    312         };
    313 
    314         /// Instantiates an argument to match a parameter, returns false if no matching results left
    315         bool instantiateArgument(
    316                 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args,
    317                 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,
    318                 unsigned nTuples = 0
    319         ) {
    320                 if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) {
    321                         // paramType is a TupleType -- group args into a TupleExpr
    322                         ++nTuples;
    323                         for ( const ast::Type * type : *tupleType ) {
    324                                 // xxx - dropping initializer changes behaviour from previous, but seems correct
    325                                 // ^^^ need to handle the case where a tuple has a default argument
    326                                 if ( ! instantiateArgument(
    327                                         type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;
    328                                 nTuples = 0;
    329                         }
    330                         // re-constitute tuples for final generation
    331                         for ( auto i = genStart; i < results.size(); ++i ) {
    332                                 results[i].endTuple( results );
    333                         }
    334                         return true;
    335                 } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) {
    336                         // paramType is a ttype, consumes all remaining arguments
    337 
    338                         // completed tuples; will be spliced to end of results to finish
    339                         std::vector< ArgPack > finalResults{};
    340 
    341                         // iterate until all results completed
    342                         std::size_t genEnd;
    343                         ++nTuples;
    344                         do {
    345                                 genEnd = results.size();
    346 
    347                                 // add another argument to results
    348                                 for ( std::size_t i = genStart; i < genEnd; ++i ) {
    349                                         unsigned nextArg = results[i].nextArg;
    350 
    351                                         // use next element of exploded tuple if present
    352                                         if ( results[i].hasExpl() ) {
    353                                                 const ExplodedArg & expl = results[i].getExpl( args );
    354 
    355                                                 unsigned nextExpl = results[i].nextExpl + 1;
    356                                                 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
    357 
    358                                                 results.emplace_back(
    359                                                         i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
    360                                                         copy( results[i].need ), copy( results[i].have ),
    361                                                         copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl,
    362                                                         results[i].explAlt );
    363 
    364                                                 continue;
    365                                         }
    366 
    367                                         // finish result when out of arguments
    368                                         if ( nextArg >= args.size() ) {
    369                                                 ArgPack newResult{
    370                                                         results[i].env, results[i].need, results[i].have, results[i].open };
    371                                                 newResult.nextArg = nextArg;
    372                                                 const ast::Type * argType = nullptr;
    373 
    374                                                 if ( nTuples > 0 || ! results[i].expr ) {
    375                                                         // first iteration or no expression to clone,
    376                                                         // push empty tuple expression
    377                                                         newResult.parent = i;
    378                                                         newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} };
    379                                                         argType = newResult.expr->result;
    380                                                 } else {
    381                                                         // clone result to collect tuple
    382                                                         newResult.parent = results[i].parent;
    383                                                         newResult.cost = results[i].cost;
    384                                                         newResult.tupleStart = results[i].tupleStart;
    385                                                         newResult.expr = results[i].expr;
    386                                                         argType = newResult.expr->result;
    387 
    388                                                         if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) {
    389                                                                 // the case where a ttype value is passed directly is special,
    390                                                                 // e.g. for argument forwarding purposes
    391                                                                 // xxx - what if passing multiple arguments, last of which is
    392                                                                 //       ttype?
    393                                                                 // xxx - what would happen if unify was changed so that unifying
    394                                                                 //       tuple
    395                                                                 // types flattened both before unifying lists? then pass in
    396                                                                 // TupleType (ttype) below.
    397                                                                 --newResult.tupleStart;
    398                                                         } else {
    399                                                                 // collapse leftover arguments into tuple
    400                                                                 newResult.endTuple( results );
    401                                                                 argType = newResult.expr->result;
    402                                                         }
    403                                                 }
    404 
    405                                                 // check unification for ttype before adding to final
    406                                                 if (
    407                                                         unify(
    408                                                                 ttype, argType, newResult.env, newResult.need, newResult.have,
    409                                                                 newResult.open, symtab )
    410                                                 ) {
    411                                                         finalResults.emplace_back( std::move( newResult ) );
    412                                                 }
    413 
    414                                                 continue;
    415                                         }
    416 
    417                                         // add each possible next argument
    418                                         for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
    419                                                 const ExplodedArg & expl = args[nextArg][j];
    420 
    421                                                 // fresh copies of parent parameters for this iteration
    422                                                 ast::TypeEnvironment env = results[i].env;
    423                                                 ast::OpenVarSet open = results[i].open;
    424 
    425                                                 env.addActual( expl.env, open );
    426 
    427                                                 // skip empty tuple arguments by (nearly) cloning parent into next gen
    428                                                 if ( expl.exprs.empty() ) {
    429                                                         results.emplace_back(
    430                                                                 results[i], std::move( env ), copy( results[i].need ),
    431                                                                 copy( results[i].have ), std::move( open ), nextArg + 1, expl.cost );
    432 
    433                                                         continue;
    434                                                 }
    435 
    436                                                 // add new result
    437                                                 results.emplace_back(
    438                                                         i, expl.exprs.front(), std::move( env ), copy( results[i].need ),
    439                                                         copy( results[i].have ), std::move( open ), nextArg + 1, nTuples,
    440                                                         expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    441                                         }
    442                                 }
    443 
    444                                 // reset for next round
    445                                 genStart = genEnd;
    446                                 nTuples = 0;
    447                         } while ( genEnd != results.size() );
    448 
    449                         // splice final results onto results
    450                         for ( std::size_t i = 0; i < finalResults.size(); ++i ) {
    451                                 results.emplace_back( std::move( finalResults[i] ) );
    452                         }
    453                         return ! finalResults.empty();
    454                 }
    455 
    456                 // iterate each current subresult
    457                 std::size_t genEnd = results.size();
    458                 for ( std::size_t i = genStart; i < genEnd; ++i ) {
    459                         unsigned nextArg = results[i].nextArg;
    460 
    461                         // use remainder of exploded tuple if present
    462                         if ( results[i].hasExpl() ) {
    463                                 const ExplodedArg & expl = results[i].getExpl( args );
    464                                 const ast::Expr * expr = expl.exprs[ results[i].nextExpl ];
    465 
    466                                 ast::TypeEnvironment env = results[i].env;
    467                                 ast::AssertionSet need = results[i].need, have = results[i].have;
    468                                 ast::OpenVarSet open = results[i].open;
    469 
    470                                 const ast::Type * argType = expr->result;
    471 
    472                                 PRINT(
    473                                         std::cerr << "param type is ";
    474                                         ast::print( std::cerr, paramType );
    475                                         std::cerr << std::endl << "arg type is ";
    476                                         ast::print( std::cerr, argType );
    477                                         std::cerr << std::endl;
    478                                 )
    479 
    480                                 if ( unify( paramType, argType, env, need, have, open, symtab ) ) {
    481                                         unsigned nextExpl = results[i].nextExpl + 1;
    482                                         if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
    483 
    484                                         results.emplace_back(
    485                                                 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), nextArg,
    486                                                 nTuples, Cost::zero, nextExpl, results[i].explAlt );
    487                                 }
    488 
    489                                 continue;
    490                         }
    491 
    492                         // use default initializers if out of arguments
    493                         if ( nextArg >= args.size() ) {
    494                                 if ( const ast::ConstantExpr * cnst = getDefaultValue( init ) ) {
    495                                         ast::TypeEnvironment env = results[i].env;
    496                                         ast::AssertionSet need = results[i].need, have = results[i].have;
    497                                         ast::OpenVarSet open = results[i].open;
    498 
    499                                         if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) {
    500                                                 results.emplace_back(
    501                                                         i, new ast::DefaultArgExpr{ cnst->location, cnst }, std::move( env ),
    502                                                         std::move( need ), std::move( have ), std::move( open ), nextArg, nTuples );
    503                                         }
    504                                 }
    505 
    506                                 continue;
    507                         }
    508 
    509                         // Check each possible next argument
    510                         for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
    511                                 const ExplodedArg & expl = args[nextArg][j];
    512 
    513                                 // fresh copies of parent parameters for this iteration
    514                                 ast::TypeEnvironment env = results[i].env;
    515                                 ast::AssertionSet need = results[i].need, have = results[i].have;
    516                                 ast::OpenVarSet open = results[i].open;
    517 
    518                                 env.addActual( expl.env, open );
    519 
    520                                 // skip empty tuple arguments by (nearly) cloning parent into next gen
    521                                 if ( expl.exprs.empty() ) {
    522                                         results.emplace_back(
    523                                                 results[i], std::move( env ), std::move( need ), std::move( have ), std::move( open ),
    524                                                 nextArg + 1, expl.cost );
    525 
    526                                         continue;
    527                                 }
    528 
    529                                 // consider only first exploded arg
    530                                 const ast::Expr * expr = expl.exprs.front();
    531                                 const ast::Type * argType = expr->result;
    532 
    533                                 PRINT(
    534                                         std::cerr << "param type is ";
    535                                         ast::print( std::cerr, paramType );
    536                                         std::cerr << std::endl << "arg type is ";
    537                                         ast::print( std::cerr, argType );
    538                                         std::cerr << std::endl;
    539                                 )
    540 
    541                                 // attempt to unify types
    542                                 if ( unify( paramType, argType, env, need, have, open, symtab ) ) {
    543                                         // add new result
    544                                         results.emplace_back(
    545                                                 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
    546                                                 nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    547                                 }
    548                         }
    549                 }
    550 
    551                 // reset for next parameter
    552                 genStart = genEnd;
    553 
    554                 return genEnd != results.size();  // were any new results added?
    555         }
    556 
    557         /// Generate a cast expression from `arg` to `toType`
    558         const ast::Expr * restructureCast(
    559                 ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast
    560         ) {
    561                 if (
    562                         arg->result->size() > 1
    563                         && ! toType->isVoid()
    564                         && ! dynamic_cast< const ast::ReferenceType * >( toType )
    565                 ) {
    566                         // Argument is a tuple and the target type is neither void nor a reference. Cast each
    567                         // member of the tuple to its corresponding target type, producing the tuple of those
    568                         // cast expressions. If there are more components of the tuple than components in the
    569                         // target type, then excess components do not come out in the result expression (but
    570                         // UniqueExpr ensures that the side effects will still be produced)
    571                         if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
    572                                 // expressions which may contain side effects require a single unique instance of
    573                                 // the expression
    574                                 arg = new ast::UniqueExpr{ arg->location, arg };
    575                         }
    576                         std::vector< ast::ptr< ast::Expr > > components;
    577                         for ( unsigned i = 0; i < toType->size(); ++i ) {
    578                                 // cast each component
    579                                 ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i };
    580                                 components.emplace_back(
    581                                         restructureCast( idx, toType->getComponent( i ), isGenerated ) );
    582                         }
    583                         return new ast::TupleExpr{ arg->location, std::move( components ) };
    584                 } else {
    585                         // handle normally
    586                         return new ast::CastExpr{ arg->location, arg, toType, isGenerated };
    587                 }
    588         }
    589 
    590         /// Gets the name from an untyped member expression (must be NameExpr)
    591         const std::string & getMemberName( const ast::UntypedMemberExpr * memberExpr ) {
    592                 if ( memberExpr->member.as< ast::ConstantExpr >() ) {
    593                         SemanticError( memberExpr, "Indexed access to struct fields unsupported: " );
    594                 }
    595 
    596                 return memberExpr->member.strict_as< ast::NameExpr >()->name;
    597         }
    598 
    599         /// Actually visits expressions to find their candidate interpretations
    600         class Finder final : public ast::WithShortCircuiting {
    601                 const ResolveContext & context;
    602                 const ast::SymbolTable & symtab;
    603         public:
    604                 // static size_t traceId;
    605                 CandidateFinder & selfFinder;
    606                 CandidateList & candidates;
    607                 const ast::TypeEnvironment & tenv;
    608                 ast::ptr< ast::Type > & targetType;
    609 
    610                 enum Errors {
    611                         NotFound,
    612                         NoMatch,
    613                         ArgsToFew,
    614                         ArgsToMany,
    615                         RetsToFew,
    616                         RetsToMany,
    617                         NoReason
    618                 };
    619 
    620                 struct {
    621                         Errors code = NotFound;
    622                 } reason;
    623 
    624                 Finder( CandidateFinder & f )
    625                 : context( f.context ), symtab( context.symtab ), selfFinder( f ),
    626                   candidates( f.candidates ), tenv( f.env ), targetType( f.targetType ) {}
    627 
    628                 void previsit( const ast::Node * ) { visit_children = false; }
    629 
    630                 /// Convenience to add candidate to list
    631                 template<typename... Args>
    632                 void addCandidate( Args &&... args ) {
    633                         candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } );
    634                         reason.code = NoReason;
    635                 }
    636 
    637                 void postvisit( const ast::ApplicationExpr * applicationExpr ) {
    638                         addCandidate( applicationExpr, tenv );
    639                 }
    640 
    641                 /// Set up candidate assertions for inference
    642                 void inferParameters( CandidateRef & newCand, CandidateList & out ) {
    643                         // Set need bindings for any unbound assertions
    644                         UniqueId crntResnSlot = 0; // matching ID for this expression's assertions
    645                         for ( auto & assn : newCand->need ) {
    646                                 // skip already-matched assertions
    647                                 if ( assn.second.resnSlot != 0 ) continue;
    648                                 // assign slot for expression if needed
    649                                 if ( crntResnSlot == 0 ) { crntResnSlot = ++globalResnSlot; }
    650                                 // fix slot to assertion
    651                                 assn.second.resnSlot = crntResnSlot;
    652                         }
    653                         // pair slot to expression
    654                         if ( crntResnSlot != 0 ) {
    655                                 newCand->expr.get_and_mutate()->inferred.resnSlots().emplace_back( crntResnSlot );
    656                         }
    657 
    658                         // add to output list; assertion satisfaction will occur later
    659                         out.emplace_back( newCand );
    660                 }
    661 
    662                 /// Completes a function candidate with arguments located
    663                 void validateFunctionCandidate(
    664                         const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,
    665                         CandidateList & out
    666                 ) {
    667                         ast::ApplicationExpr * appExpr =
    668                                 new ast::ApplicationExpr{ func->expr->location, func->expr };
    669                         // sum cost and accumulate arguments
    670                         std::deque< const ast::Expr * > args;
    671                         Cost cost = func->cost;
    672                         const ArgPack * pack = &result;
    673                         while ( pack->expr ) {
    674                                 args.emplace_front( pack->expr );
    675                                 cost += pack->cost;
    676                                 pack = &results[pack->parent];
    677                         }
    678                         std::vector< ast::ptr< ast::Expr > > vargs( args.begin(), args.end() );
    679                         appExpr->args = std::move( vargs );
    680                         // build and validate new candidate
    681                         auto newCand =
    682                                 std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost );
    683                         PRINT(
    684                                 std::cerr << "instantiate function success: " << appExpr << std::endl;
    685                                 std::cerr << "need assertions:" << std::endl;
    686                                 ast::print( std::cerr, result.need, 2 );
    687                         )
    688                         inferParameters( newCand, out );
    689                 }
    690 
    691                 /// Builds a list of candidates for a function, storing them in out
    692                 void makeFunctionCandidates(
    693                         const CandidateRef & func, const ast::FunctionType * funcType,
    694                         const ExplodedArgs_new & args, CandidateList & out
    695                 ) {
    696                         ast::OpenVarSet funcOpen;
    697                         ast::AssertionSet funcNeed, funcHave;
    698                         ast::TypeEnvironment funcEnv{ func->env };
    699                         makeUnifiableVars( funcType, funcOpen, funcNeed );
    700                         // add all type variables as open variables now so that those not used in the
    701                         // parameter list are still considered open
    702                         funcEnv.add( funcType->forall );
    703 
    704                         if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) {
    705                                 // attempt to narrow based on expected target type
    706                                 const ast::Type * returnType = funcType->returns.front();
    707                                 if ( ! unify(
    708                                         returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab )
    709                                 ) {
    710                                         // unification failed, do not pursue this candidate
    711                                         return;
    712                                 }
    713                         }
    714 
    715                         // iteratively build matches, one parameter at a time
    716                         std::vector< ArgPack > results;
    717                         results.emplace_back( funcEnv, funcNeed, funcHave, funcOpen );
    718                         std::size_t genStart = 0;
    719 
    720                         // xxx - how to handle default arg after change to ftype representation?
    721                         if (const ast::VariableExpr * varExpr = func->expr.as<ast::VariableExpr>()) {
    722                                 if (const ast::FunctionDecl * funcDecl = varExpr->var.as<ast::FunctionDecl>()) {
    723                                         // function may have default args only if directly calling by name
    724                                         // must use types on candidate however, due to RenameVars substitution
    725                                         auto nParams = funcType->params.size();
    726 
    727                                         for (size_t i=0; i<nParams; ++i) {
    728                                                 auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>();
    729                                                 if (!instantiateArgument(
    730                                                         funcType->params[i], obj->init, args, results, genStart, symtab)) return;
    731                                         }
    732                                         goto endMatch;
    733                                 }
    734                         }
    735                         for ( const auto & param : funcType->params ) {
    736                                 // Try adding the arguments corresponding to the current parameter to the existing
    737                                 // matches
    738                                 // no default args for indirect calls
    739                                 if ( ! instantiateArgument(
    740                                         param, nullptr, args, results, genStart, symtab ) ) return;
    741                         }
    742 
    743                         endMatch:
    744                         if ( funcType->isVarArgs ) {
    745                                 // append any unused arguments to vararg pack
    746                                 std::size_t genEnd;
    747                                 do {
    748                                         genEnd = results.size();
    749 
    750                                         // iterate results
    751                                         for ( std::size_t i = genStart; i < genEnd; ++i ) {
    752                                                 unsigned nextArg = results[i].nextArg;
    753 
    754                                                 // use remainder of exploded tuple if present
    755                                                 if ( results[i].hasExpl() ) {
    756                                                         const ExplodedArg & expl = results[i].getExpl( args );
    757 
    758                                                         unsigned nextExpl = results[i].nextExpl + 1;
    759                                                         if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
    760 
    761                                                         results.emplace_back(
    762                                                                 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
    763                                                                 copy( results[i].need ), copy( results[i].have ),
    764                                                                 copy( results[i].open ), nextArg, 0, Cost::zero, nextExpl,
    765                                                                 results[i].explAlt );
    766 
    767                                                         continue;
    768                                                 }
    769 
    770                                                 // finish result when out of arguments
    771                                                 if ( nextArg >= args.size() ) {
    772                                                         validateFunctionCandidate( func, results[i], results, out );
    773 
    774                                                         continue;
    775                                                 }
    776 
    777                                                 // add each possible next argument
    778                                                 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
    779                                                         const ExplodedArg & expl = args[nextArg][j];
    780 
    781                                                         // fresh copies of parent parameters for this iteration
    782                                                         ast::TypeEnvironment env = results[i].env;
    783                                                         ast::OpenVarSet open = results[i].open;
    784 
    785                                                         env.addActual( expl.env, open );
    786 
    787                                                         // skip empty tuple arguments by (nearly) cloning parent into next gen
    788                                                         if ( expl.exprs.empty() ) {
    789                                                                 results.emplace_back(
    790                                                                         results[i], std::move( env ), copy( results[i].need ),
    791                                                                         copy( results[i].have ), std::move( open ), nextArg + 1,
    792                                                                         expl.cost );
    793 
    794                                                                 continue;
    795                                                         }
    796 
    797                                                         // add new result
    798                                                         results.emplace_back(
    799                                                                 i, expl.exprs.front(), std::move( env ), copy( results[i].need ),
    800                                                                 copy( results[i].have ), std::move( open ), nextArg + 1, 0, expl.cost,
    801                                                                 expl.exprs.size() == 1 ? 0 : 1, j );
    802                                                 }
    803                                         }
    804 
    805                                         genStart = genEnd;
    806                                 } while( genEnd != results.size() );
    807                         } else {
    808                                 // filter out the results that don't use all the arguments
    809                                 for ( std::size_t i = genStart; i < results.size(); ++i ) {
    810                                         ArgPack & result = results[i];
    811                                         if ( ! result.hasExpl() && result.nextArg >= args.size() ) {
    812                                                 validateFunctionCandidate( func, result, results, out );
    813                                         }
    814                                 }
    815                         }
    816                 }
    817 
    818                 /// Adds implicit struct-conversions to the alternative list
    819                 void addAnonConversions( const CandidateRef & cand ) {
    820                         // adds anonymous member interpretations whenever an aggregate value type is seen.
    821                         // it's okay for the aggregate expression to have reference type -- cast it to the
    822                         // base type to treat the aggregate as the referenced value
    823                         ast::ptr< ast::Expr > aggrExpr( cand->expr );
    824                         ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result;
    825                         cand->env.apply( aggrType );
    826 
    827                         if ( aggrType.as< ast::ReferenceType >() ) {
    828                                 aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() };
    829                         }
    830 
    831                         if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) {
    832                                 addAggMembers( structInst, aggrExpr, *cand, Cost::safe, "" );
    833                         } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) {
    834                                 addAggMembers( unionInst, aggrExpr, *cand, Cost::safe, "" );
    835                         }
    836                 }
    837 
    838                 /// Adds aggregate member interpretations
    839                 void addAggMembers(
    840                         const ast::BaseInstType * aggrInst, const ast::Expr * expr,
    841                         const Candidate & cand, const Cost & addedCost, const std::string & name
    842                 ) {
    843                         for ( const ast::Decl * decl : aggrInst->lookup( name ) ) {
    844                                 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl );
    845                                 CandidateRef newCand = std::make_shared<Candidate>(
    846                                         cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost );
    847                                 // add anonymous member interpretations whenever an aggregate value type is seen
    848                                 // as a member expression
    849                                 addAnonConversions( newCand );
    850                                 candidates.emplace_back( std::move( newCand ) );
    851                         }
    852                 }
    853 
    854                 /// Adds tuple member interpretations
    855                 void addTupleMembers(
    856                         const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,
    857                         const Cost & addedCost, const ast::Expr * member
    858                 ) {
    859                         if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) {
    860                                 // get the value of the constant expression as an int, must be between 0 and the
    861                                 // length of the tuple to have meaning
    862                                 long long val = constantExpr->intValue();
    863                                 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {
    864                                         addCandidate(
    865                                                 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val },
    866                                                 addedCost );
    867                                 }
    868                         }
    869                 }
    870 
    871                 void postvisit( const ast::UntypedExpr * untypedExpr ) {
    872                         std::vector< CandidateFinder > argCandidates =
    873                                 selfFinder.findSubExprs( untypedExpr->args );
    874 
    875                         // take care of possible tuple assignments
    876                         // if not tuple assignment, handled as normal function call
    877                         Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates );
    878 
    879                         CandidateFinder funcFinder( context, tenv );
    880                         if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) {
    881                                 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
    882                                 if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) {
    883                                         assertf(!argCandidates.empty(), "special function call without argument");
    884                                         for (auto & firstArgCand: argCandidates[0]) {
    885                                                 ast::ptr<ast::Type> argType = firstArgCand->expr->result;
    886                                                 firstArgCand->env.apply(argType);
    887                                                 // strip references
    888                                                 // xxx - is this correct?
    889                                                 while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base;
    890 
    891                                                 // convert 1-tuple to plain type
    892                                                 if (auto tuple = argType.as<ast::TupleType>()) {
    893                                                         if (tuple->size() == 1) {
    894                                                                 argType = tuple->types[0];
    895                                                         }
    896                                                 }
    897 
    898                                                 // if argType is an unbound type parameter, all special functions need to be searched.
    899                                                 if (isUnboundType(argType)) {
    900                                                         funcFinder.otypeKeys.clear();
    901                                                         break;
    902                                                 }
    903 
    904                                                 if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer);                                             
    905                                                 // else if (const ast::EnumInstType * enumInst = argType.as<ast::EnumInstType>()) {
    906                                                 //      const ast::EnumDecl * enumDecl = enumInst->base; // Here
    907                                                 //      if ( const ast::Type* enumType = enumDecl->base ) {
    908                                                 //              // instance of enum (T) is a instance of type (T)
    909                                                 //              funcFinder.otypeKeys.insert(Mangle::mangle(enumType, Mangle::NoGenericParams | Mangle::Type));
    910                                                 //      } else {
    911                                                 //              // instance of an untyped enum is techically int
    912                                                 //              funcFinder.otypeKeys.insert(Mangle::mangle(enumDecl, Mangle::NoGenericParams | Mangle::Type));
    913                                                 //      }
    914                                                 // }
    915                                                 else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type));
    916                                         }
    917                                 }
    918                         }
    919                         // if candidates are already produced, do not fail
    920                         // xxx - is it possible that handleTupleAssignment and main finder both produce candidates?
    921                         // this means there exists ctor/assign functions with a tuple as first parameter.
    922                         ResolvMode mode = {
    923                                 true, // adjust
    924                                 !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name
    925                                 selfFinder.candidates.empty() // failfast if other options are not found
    926                         };
    927                         funcFinder.find( untypedExpr->func, mode );
    928                         // short-circuit if no candidates
    929                         // if ( funcFinder.candidates.empty() ) return;
    930 
    931                         reason.code = NoMatch;
    932 
    933                         // find function operators
    934                         ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" }; // ??? why not ?{}
    935                         CandidateFinder opFinder( context, tenv );
    936                         // okay if there aren't any function operations
    937                         opFinder.find( opExpr, ResolvMode::withoutFailFast() );
    938                         PRINT(
    939                                 std::cerr << "known function ops:" << std::endl;
    940                                 print( std::cerr, opFinder.candidates, 1 );
    941                         )
    942 
    943                         // pre-explode arguments
    944                         ExplodedArgs_new argExpansions;
    945                         for ( const CandidateFinder & args : argCandidates ) {
    946                                 argExpansions.emplace_back();
    947                                 auto & argE = argExpansions.back();
    948                                 for ( const CandidateRef & arg : args ) { argE.emplace_back( *arg, symtab ); }
    949                         }
    950 
    951                         // Find function matches
    952                         CandidateList found;
    953                         SemanticErrorException errors;
    954                         for ( CandidateRef & func : funcFinder ) {
    955                                 try {
    956                                         PRINT(
    957                                                 std::cerr << "working on alternative:" << std::endl;
    958                                                 print( std::cerr, *func, 2 );
    959                                         )
    960 
    961                                         // check if the type is a pointer to function
    962                                         const ast::Type * funcResult = func->expr->result->stripReferences();
    963                                         if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) {
    964                                                 if ( auto function = pointer->base.as< ast::FunctionType >() ) {
    965                                                         CandidateRef newFunc{ new Candidate{ *func } };
    966                                                         newFunc->expr =
    967                                                                 referenceToRvalueConversion( newFunc->expr, newFunc->cost );
    968                                                         makeFunctionCandidates( newFunc, function, argExpansions, found );
    969                                                 }
    970                                         } else if (
    971                                                 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )
    972                                         ) {
    973                                                 if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) {
    974                                                         if ( auto function = clz->bound.as< ast::FunctionType >() ) {
    975                                                                 CandidateRef newFunc{ new Candidate{ *func } };
    976                                                                 newFunc->expr =
    977                                                                         referenceToRvalueConversion( newFunc->expr, newFunc->cost );
    978                                                                 makeFunctionCandidates( newFunc, function, argExpansions, found );
    979                                                         }
    980                                                 }
    981                                         }
    982                                 } catch ( SemanticErrorException & e ) { errors.append( e ); }
    983                         }
    984 
    985                         // Find matches on function operators `?()`
    986                         if ( ! opFinder.candidates.empty() ) {
    987                                 // add exploded function alternatives to front of argument list
    988                                 std::vector< ExplodedArg > funcE;
    989                                 funcE.reserve( funcFinder.candidates.size() );
    990                                 for ( const CandidateRef & func : funcFinder ) {
    991                                         funcE.emplace_back( *func, symtab );
    992                                 }
    993                                 argExpansions.emplace_front( std::move( funcE ) );
    994 
    995                                 for ( const CandidateRef & op : opFinder ) {
    996                                         try {
    997                                                 // check if type is pointer-to-function
    998                                                 const ast::Type * opResult = op->expr->result->stripReferences();
    999                                                 if ( auto pointer = dynamic_cast< const ast::PointerType * >( opResult ) ) {
    1000                                                         if ( auto function = pointer->base.as< ast::FunctionType >() ) {
    1001                                                                 CandidateRef newOp{ new Candidate{ *op} };
    1002                                                                 newOp->expr =
    1003                                                                         referenceToRvalueConversion( newOp->expr, newOp->cost );
    1004                                                                 makeFunctionCandidates( newOp, function, argExpansions, found );
    1005                                                         }
    1006                                                 }
    1007                                         } catch ( SemanticErrorException & e ) { errors.append( e ); }
    1008                                 }
    1009                         }
    1010 
    1011                         // Implement SFINAE; resolution errors are only errors if there aren't any non-error
    1012                         // candidates
    1013                         if ( found.empty() && ! errors.isEmpty() ) { throw errors; }
    1014 
    1015                         // Compute conversion costs
    1016                         for ( CandidateRef & withFunc : found ) {
    1017                                 Cost cvtCost = computeApplicationConversionCost( withFunc, symtab );
    1018 
    1019                                 PRINT(
    1020                                         auto appExpr = withFunc->expr.strict_as< ast::ApplicationExpr >();
    1021                                         auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
    1022                                         auto function = pointer->base.strict_as< ast::FunctionType >();
    1023 
    1024                                         std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl;
    1025                                         std::cerr << "parameters are:" << std::endl;
    1026                                         ast::printAll( std::cerr, function->params, 2 );
    1027                                         std::cerr << "arguments are:" << std::endl;
    1028                                         ast::printAll( std::cerr, appExpr->args, 2 );
    1029                                         std::cerr << "bindings are:" << std::endl;
    1030                                         ast::print( std::cerr, withFunc->env, 2 );
    1031                                         std::cerr << "cost is: " << withFunc->cost << std::endl;
    1032                                         std::cerr << "cost of conversion is:" << cvtCost << std::endl;
    1033                                 )
    1034 
    1035                                 if ( cvtCost != Cost::infinity ) {
    1036                                         withFunc->cvtCost = cvtCost;
    1037                                         candidates.emplace_back( std::move( withFunc ) );
    1038                                 }
    1039                         }
    1040                         found = std::move( candidates );
    1041 
    1042                         // use a new list so that candidates are not examined by addAnonConversions twice
    1043                         CandidateList winners = findMinCost( found );
    1044                         promoteCvtCost( winners );
    1045 
    1046                         // function may return a struct/union value, in which case we need to add candidates
    1047                         // for implicit conversions to each of the anonymous members, which must happen after
    1048                         // `findMinCost`, since anon conversions are never the cheapest
    1049                         for ( const CandidateRef & c : winners ) {
    1050                                 addAnonConversions( c );
    1051                         }
    1052                         spliceBegin( candidates, winners );
    1053 
    1054                         if ( candidates.empty() && targetType && ! targetType->isVoid() ) {
    1055                                 // If resolution is unsuccessful with a target type, try again without, since it
    1056                                 // will sometimes succeed when it wouldn't with a target type binding.
    1057                                 // For example:
    1058                                 //   forall( otype T ) T & ?[]( T *, ptrdiff_t );
    1059                                 //   const char * x = "hello world";
    1060                                 //   unsigned char ch = x[0];
    1061                                 // Fails with simple return type binding (xxx -- check this!) as follows:
    1062                                 // * T is bound to unsigned char
    1063                                 // * (x: const char *) is unified with unsigned char *, which fails
    1064                                 // xxx -- fix this better
    1065                                 targetType = nullptr;
    1066                                 postvisit( untypedExpr );
    1067                         }
    1068                 }
    1069 
    1070                 /// true if expression is an lvalue
    1071                 static bool isLvalue( const ast::Expr * x ) {
    1072                         return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() );
    1073                 }
    1074 
    1075                 void postvisit( const ast::AddressExpr * addressExpr ) {
    1076                         CandidateFinder finder( context, tenv );
    1077                         finder.find( addressExpr->arg );
    1078 
    1079                         if( finder.candidates.empty() ) return;
    1080 
    1081                         reason.code = NoMatch;
    1082 
    1083                         for ( CandidateRef & r : finder.candidates ) {
    1084                                 if ( ! isLvalue( r->expr ) ) continue;
    1085                                 addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } );
    1086                         }
    1087                 }
    1088 
    1089                 void postvisit( const ast::LabelAddressExpr * labelExpr ) {
    1090                         addCandidate( labelExpr, tenv );
    1091                 }
    1092 
    1093                 void postvisit( const ast::CastExpr * castExpr ) {
    1094                         ast::ptr< ast::Type > toType = castExpr->result;
    1095                         assert( toType );
    1096                         toType = resolveTypeof( toType, context );
    1097                         toType = adjustExprType( toType, tenv, symtab );
    1098 
    1099                         CandidateFinder finder( context, tenv, toType );
    1100                         finder.find( castExpr->arg, ResolvMode::withAdjustment() );
    1101 
    1102                         if( !finder.candidates.empty() ) reason.code = NoMatch;
    1103 
    1104                         CandidateList matches;
    1105                         for ( CandidateRef & cand : finder.candidates ) {
    1106                                 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
    1107                                 ast::OpenVarSet open( cand->open );
    1108 
    1109                                 cand->env.extractOpenVars( open );
    1110 
    1111                                 // It is possible that a cast can throw away some values in a multiply-valued
    1112                                 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the
    1113                                 // subexpression results that are cast directly. The candidate is invalid if it
    1114                                 // has fewer results than there are types to cast to.
    1115                                 int discardedValues = cand->expr->result->size() - toType->size();
    1116                                 if ( discardedValues < 0 ) continue;
    1117 
    1118                                 // unification run for side-effects
    1119                                 unify( toType, cand->expr->result, cand->env, need, have, open, symtab );
    1120                                 Cost thisCost =
    1121                                         (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast)
    1122                             ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env )
    1123                             : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env );
    1124 
    1125                                 PRINT(
    1126                                         std::cerr << "working on cast with result: " << toType << std::endl;
    1127                                         std::cerr << "and expr type: " << cand->expr->result << std::endl;
    1128                                         std::cerr << "env: " << cand->env << std::endl;
    1129                                 )
    1130                                 if ( thisCost != Cost::infinity ) {
    1131                                         PRINT(
    1132                                                 std::cerr << "has finite cost." << std::endl;
    1133                                         )
    1134                                         // count one safe conversion for each value that is thrown away
    1135                                         thisCost.incSafe( discardedValues );
    1136                                         CandidateRef newCand = std::make_shared<Candidate>(
    1137                                                 restructureCast( cand->expr, toType, castExpr->isGenerated ),
    1138                                                 copy( cand->env ), std::move( open ), std::move( need ), cand->cost,
    1139                                                 cand->cost + thisCost );
    1140                                         inferParameters( newCand, matches );
    1141                                 }
    1142                         }
    1143 
    1144                         // select first on argument cost, then conversion cost
    1145                         CandidateList minArgCost = findMinCost( matches );
    1146                         promoteCvtCost( minArgCost );
    1147                         candidates = findMinCost( minArgCost );
    1148                 }
    1149 
    1150                 void postvisit( const ast::VirtualCastExpr * castExpr ) {
    1151                         assertf( castExpr->result, "Implicit virtual cast targets not yet supported." );
    1152                         CandidateFinder finder( context, tenv );
    1153                         // don't prune here, all alternatives guaranteed to have same type
    1154                         finder.find( castExpr->arg, ResolvMode::withoutPrune() );
    1155                         for ( CandidateRef & r : finder.candidates ) {
    1156                                 addCandidate(
    1157                                         *r,
    1158                                         new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );
    1159                         }
    1160                 }
    1161 
    1162                 void postvisit( const ast::KeywordCastExpr * castExpr ) {
    1163                         const auto & loc = castExpr->location;
    1164                         assertf( castExpr->result, "Cast target should have been set in Validate." );
    1165                         auto ref = castExpr->result.strict_as<ast::ReferenceType>();
    1166                         auto inst = ref->base.strict_as<ast::StructInstType>();
    1167                         auto target = inst->base.get();
    1168 
    1169                         CandidateFinder finder( context, tenv );
    1170 
    1171                         auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) {
    1172                                 for(auto & cand : found) {
    1173                                         const ast::Type * expr = cand->expr->result.get();
    1174                                         if(expect_ref) {
    1175                                                 auto res = dynamic_cast<const ast::ReferenceType*>(expr);
    1176                                                 if(!res) { continue; }
    1177                                                 expr = res->base.get();
    1178                                         }
    1179 
    1180                                         if(auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) {
    1181                                                 auto td = cand->env.lookup(*insttype);
    1182                                                 if(!td) { continue; }
    1183                                                 expr = td->bound.get();
    1184                                         }
    1185 
    1186                                         if(auto base = dynamic_cast<const ast::StructInstType*>(expr)) {
    1187                                                 if(base->base == target) {
    1188                                                         candidates.push_back( std::move(cand) );
    1189                                                         reason.code = NoReason;
    1190                                                 }
    1191                                         }
    1192                                 }
    1193                         };
    1194 
    1195                         try {
    1196                                 // Attempt 1 : turn (thread&)X into (thread$&)X.__thrd
    1197                                 // Clone is purely for memory management
    1198                                 std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) };
    1199 
    1200                                 // don't prune here, since it's guaranteed all alternatives will have the same type
    1201                                 finder.find( tech1.get(), ResolvMode::withoutPrune() );
    1202                                 pick_alternatives(finder.candidates, false);
    1203 
    1204                                 return;
    1205                         } catch(SemanticErrorException & ) {}
    1206 
    1207                         // Fallback : turn (thread&)X into (thread$&)get_thread(X)
    1208                         std::unique_ptr<const ast::Expr> fallback { ast::UntypedExpr::createDeref(loc,  new ast::UntypedExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.getter), { castExpr->arg })) };
    1209                         // don't prune here, since it's guaranteed all alternatives will have the same type
    1210                         finder.find( fallback.get(), ResolvMode::withoutPrune() );
    1211 
    1212                         pick_alternatives(finder.candidates, true);
    1213 
    1214                         // Whatever happens here, we have no more fallbacks
    1215                 }
    1216 
    1217                 void postvisit( const ast::UntypedMemberExpr * memberExpr ) {
    1218                         CandidateFinder aggFinder( context, tenv );
    1219                         aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() );
    1220                         for ( CandidateRef & agg : aggFinder.candidates ) {
    1221                                 // it's okay for the aggregate expression to have reference type -- cast it to the
    1222                                 // base type to treat the aggregate as the referenced value
    1223                                 Cost addedCost = Cost::zero;
    1224                                 agg->expr = referenceToRvalueConversion( agg->expr, addedCost );
    1225 
    1226                                 // find member of the given type
    1227                                 if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) {
    1228                                         addAggMembers(
    1229                                                 structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
    1230                                 } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) {
    1231                                         addAggMembers(
    1232                                                 unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
    1233                                 } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) {
    1234                                         addTupleMembers( tupleType, agg->expr, *agg, addedCost, memberExpr->member );
    1235                                 }
    1236                         }
    1237                 }
    1238 
    1239                 void postvisit( const ast::MemberExpr * memberExpr ) {
    1240                         addCandidate( memberExpr, tenv );
    1241                 }
    1242 
    1243                 void postvisit( const ast::NameExpr * nameExpr ) {
    1244                         std::vector< ast::SymbolTable::IdData > declList;
    1245                         if (!selfFinder.otypeKeys.empty()) {
    1246                                 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
    1247                                 assertf(kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS, "special lookup with non-special target: %s", nameExpr->name.c_str());
    1248 
    1249                                 for (auto & otypeKey: selfFinder.otypeKeys) {
    1250                                         auto result = symtab.specialLookupId(kind, otypeKey);
    1251                                         declList.insert(declList.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end()));
    1252                                 }
    1253                         }
    1254                         else {
    1255                                 declList = symtab.lookupId( nameExpr->name );
    1256                         }
    1257                         PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
    1258 
    1259                         if( declList.empty() ) return;
    1260 
    1261                         reason.code = NoMatch;
    1262 
    1263                         for ( auto & data : declList ) {
    1264                                 Cost cost = Cost::zero;
    1265                                 ast::Expr * newExpr = data.combine( nameExpr->location, cost );
    1266 
    1267                                 CandidateRef newCand = std::make_shared<Candidate>(
    1268                                         newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
    1269                                         cost );
    1270 
    1271                                 if (newCand->expr->env) {
    1272                                         newCand->env.add(*newCand->expr->env);
    1273                                         auto mutExpr = newCand->expr.get_and_mutate();
    1274                                         mutExpr->env  = nullptr;
    1275                                         newCand->expr = mutExpr;
    1276                                 }
    1277 
    1278                                 PRINT(
    1279                                         std::cerr << "decl is ";
    1280                                         ast::print( std::cerr, data.id );
    1281                                         std::cerr << std::endl;
    1282                                         std::cerr << "newExpr is ";
    1283                                         ast::print( std::cerr, newExpr );
    1284                                         std::cerr << std::endl;
    1285                                 )
    1286                                 newCand->expr = ast::mutate_field(
    1287                                         newCand->expr.get(), &ast::Expr::result,
    1288                                         renameTyVars( newCand->expr->result ) );
    1289                                 // add anonymous member interpretations whenever an aggregate value type is seen
    1290                                 // as a name expression
    1291                                 addAnonConversions( newCand );
    1292                                 candidates.emplace_back( std::move( newCand ) );
    1293                         }
    1294                 }
    1295 
    1296                 void postvisit( const ast::VariableExpr * variableExpr ) {
    1297                         // not sufficient to just pass `variableExpr` here, type might have changed since
    1298                         // creation
    1299                         addCandidate(
    1300                                 new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv );
    1301                 }
    1302 
    1303                 void postvisit( const ast::ConstantExpr * constantExpr ) {
    1304                         addCandidate( constantExpr, tenv );
    1305                 }
    1306 
    1307                 void postvisit( const ast::SizeofExpr * sizeofExpr ) {
    1308                         if ( sizeofExpr->type ) {
    1309                                 addCandidate(
    1310                                         new ast::SizeofExpr{
    1311                                                 sizeofExpr->location, resolveTypeof( sizeofExpr->type, context ) },
    1312                                         tenv );
    1313                         } else {
    1314                                 // find all candidates for the argument to sizeof
    1315                                 CandidateFinder finder( context, tenv );
    1316                                 finder.find( sizeofExpr->expr );
    1317                                 // find the lowest-cost candidate, otherwise ambiguous
    1318                                 CandidateList winners = findMinCost( finder.candidates );
    1319                                 if ( winners.size() != 1 ) {
    1320                                         SemanticError(
    1321                                                 sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " );
    1322                                 }
    1323                                 // return the lowest-cost candidate
    1324                                 CandidateRef & choice = winners.front();
    1325                                 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
    1326                                 choice->cost = Cost::zero;
    1327                                 addCandidate( *choice, new ast::SizeofExpr{ sizeofExpr->location, choice->expr } );
    1328                         }
    1329                 }
    1330 
    1331                 void postvisit( const ast::AlignofExpr * alignofExpr ) {
    1332                         if ( alignofExpr->type ) {
    1333                                 addCandidate(
    1334                                         new ast::AlignofExpr{
    1335                                                 alignofExpr->location, resolveTypeof( alignofExpr->type, context ) },
    1336                                         tenv );
    1337                         } else {
    1338                                 // find all candidates for the argument to alignof
    1339                                 CandidateFinder finder( context, tenv );
    1340                                 finder.find( alignofExpr->expr );
    1341                                 // find the lowest-cost candidate, otherwise ambiguous
    1342                                 CandidateList winners = findMinCost( finder.candidates );
    1343                                 if ( winners.size() != 1 ) {
    1344                                         SemanticError(
    1345                                                 alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " );
    1346                                 }
    1347                                 // return the lowest-cost candidate
    1348                                 CandidateRef & choice = winners.front();
    1349                                 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
    1350                                 choice->cost = Cost::zero;
    1351                                 addCandidate(
    1352                                         *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } );
    1353                         }
    1354                 }
    1355 
    1356                 void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) {
    1357                         const ast::BaseInstType * aggInst;
    1358                         if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ;
    1359                         else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ;
    1360                         else return;
    1361 
    1362                         for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) {
    1363                                 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member );
    1364                                 addCandidate(
    1365                                         new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv );
    1366                         }
    1367                 }
    1368 
    1369                 void postvisit( const ast::OffsetofExpr * offsetofExpr ) {
    1370                         addCandidate( offsetofExpr, tenv );
    1371                 }
    1372 
    1373                 void postvisit( const ast::OffsetPackExpr * offsetPackExpr ) {
    1374                         addCandidate( offsetPackExpr, tenv );
    1375                 }
    1376 
    1377                 void postvisit( const ast::LogicalExpr * logicalExpr ) {
    1378                         CandidateFinder finder1( context, tenv );
    1379                         finder1.find( logicalExpr->arg1, ResolvMode::withAdjustment() );
    1380                         if ( finder1.candidates.empty() ) return;
    1381 
    1382                         CandidateFinder finder2( context, tenv );
    1383                         finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() );
    1384                         if ( finder2.candidates.empty() ) return;
    1385 
    1386                         reason.code = NoMatch;
    1387 
    1388                         for ( const CandidateRef & r1 : finder1.candidates ) {
    1389                                 for ( const CandidateRef & r2 : finder2.candidates ) {
    1390                                         ast::TypeEnvironment env{ r1->env };
    1391                                         env.simpleCombine( r2->env );
    1392                                         ast::OpenVarSet open{ r1->open };
    1393                                         mergeOpenVars( open, r2->open );
    1394                                         ast::AssertionSet need;
    1395                                         mergeAssertionSet( need, r1->need );
    1396                                         mergeAssertionSet( need, r2->need );
    1397 
    1398                                         addCandidate(
    1399                                                 new ast::LogicalExpr{
    1400                                                         logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd },
    1401                                                 std::move( env ), std::move( open ), std::move( need ), r1->cost + r2->cost );
    1402                                 }
    1403                         }
    1404                 }
    1405 
    1406                 void postvisit( const ast::ConditionalExpr * conditionalExpr ) {
    1407                         // candidates for condition
    1408                         CandidateFinder finder1( context, tenv );
    1409                         finder1.find( conditionalExpr->arg1, ResolvMode::withAdjustment() );
    1410                         if ( finder1.candidates.empty() ) return;
    1411 
    1412                         // candidates for true result
    1413                         CandidateFinder finder2( context, tenv );
    1414                         finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() );
    1415                         if ( finder2.candidates.empty() ) return;
    1416 
    1417                         // candidates for false result
    1418                         CandidateFinder finder3( context, tenv );
    1419                         finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );
    1420                         if ( finder3.candidates.empty() ) return;
    1421 
    1422                         reason.code = NoMatch;
    1423 
    1424                         for ( const CandidateRef & r1 : finder1.candidates ) {
    1425                                 for ( const CandidateRef & r2 : finder2.candidates ) {
    1426                                         for ( const CandidateRef & r3 : finder3.candidates ) {
    1427                                                 ast::TypeEnvironment env{ r1->env };
    1428                                                 env.simpleCombine( r2->env );
    1429                                                 env.simpleCombine( r3->env );
    1430                                                 ast::OpenVarSet open{ r1->open };
    1431                                                 mergeOpenVars( open, r2->open );
    1432                                                 mergeOpenVars( open, r3->open );
    1433                                                 ast::AssertionSet need;
    1434                                                 mergeAssertionSet( need, r1->need );
    1435                                                 mergeAssertionSet( need, r2->need );
    1436                                                 mergeAssertionSet( need, r3->need );
    1437                                                 ast::AssertionSet have;
    1438 
    1439                                                 // unify true and false results, then infer parameters to produce new
    1440                                                 // candidates
    1441                                                 ast::ptr< ast::Type > common;
    1442                                                 if (
    1443                                                         unify(
    1444                                                                 r2->expr->result, r3->expr->result, env, need, have, open, symtab,
    1445                                                                 common )
    1446                                                 ) {
    1447                                                         // generate typed expression
    1448                                                         ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{
    1449                                                                 conditionalExpr->location, r1->expr, r2->expr, r3->expr };
    1450                                                         newExpr->result = common ? common : r2->expr->result;
    1451                                                         // convert both options to result type
    1452                                                         Cost cost = r1->cost + r2->cost + r3->cost;
    1453                                                         newExpr->arg2 = computeExpressionConversionCost(
    1454                                                                 newExpr->arg2, newExpr->result, symtab, env, cost );
    1455                                                         newExpr->arg3 = computeExpressionConversionCost(
    1456                                                                 newExpr->arg3, newExpr->result, symtab, env, cost );
    1457                                                         // output candidate
    1458                                                         CandidateRef newCand = std::make_shared<Candidate>(
    1459                                                                 newExpr, std::move( env ), std::move( open ), std::move( need ), cost );
    1460                                                         inferParameters( newCand, candidates );
    1461                                                 }
    1462                                         }
    1463                                 }
    1464                         }
    1465                 }
    1466 
    1467                 void postvisit( const ast::CommaExpr * commaExpr ) {
    1468                         ast::TypeEnvironment env{ tenv };
    1469                         ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, context, env );
    1470 
    1471                         CandidateFinder finder2( context, env );
    1472                         finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() );
    1473 
    1474                         for ( const CandidateRef & r2 : finder2.candidates ) {
    1475                                 addCandidate( *r2, new ast::CommaExpr{ commaExpr->location, arg1, r2->expr } );
    1476                         }
    1477                 }
    1478 
    1479                 void postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ) {
    1480                         addCandidate( ctorExpr, tenv );
    1481                 }
    1482 
    1483                 void postvisit( const ast::ConstructorExpr * ctorExpr ) {
    1484                         CandidateFinder finder( context, tenv );
    1485                         finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() );
    1486                         for ( CandidateRef & r : finder.candidates ) {
    1487                                 addCandidate( *r, new ast::ConstructorExpr{ ctorExpr->location, r->expr } );
    1488                         }
    1489                 }
    1490 
    1491                 void postvisit( const ast::RangeExpr * rangeExpr ) {
    1492                         // resolve low and high, accept candidates where low and high types unify
    1493                         CandidateFinder finder1( context, tenv );
    1494                         finder1.find( rangeExpr->low, ResolvMode::withAdjustment() );
    1495                         if ( finder1.candidates.empty() ) return;
    1496 
    1497                         CandidateFinder finder2( context, tenv );
    1498                         finder2.find( rangeExpr->high, ResolvMode::withAdjustment() );
    1499                         if ( finder2.candidates.empty() ) return;
    1500 
    1501                         reason.code = NoMatch;
    1502 
    1503                         for ( const CandidateRef & r1 : finder1.candidates ) {
    1504                                 for ( const CandidateRef & r2 : finder2.candidates ) {
    1505                                         ast::TypeEnvironment env{ r1->env };
    1506                                         env.simpleCombine( r2->env );
    1507                                         ast::OpenVarSet open{ r1->open };
    1508                                         mergeOpenVars( open, r2->open );
    1509                                         ast::AssertionSet need;
    1510                                         mergeAssertionSet( need, r1->need );
    1511                                         mergeAssertionSet( need, r2->need );
    1512                                         ast::AssertionSet have;
    1513 
    1514                                         ast::ptr< ast::Type > common;
    1515                                         if (
    1516                                                 unify(
    1517                                                         r1->expr->result, r2->expr->result, env, need, have, open, symtab,
    1518                                                         common )
    1519                                         ) {
    1520                                                 // generate new expression
    1521                                                 ast::RangeExpr * newExpr =
    1522                                                         new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };
    1523                                                 newExpr->result = common ? common : r1->expr->result;
    1524                                                 // add candidate
    1525                                                 CandidateRef newCand = std::make_shared<Candidate>(
    1526                                                         newExpr, std::move( env ), std::move( open ), std::move( need ),
    1527                                                         r1->cost + r2->cost );
    1528                                                 inferParameters( newCand, candidates );
    1529                                         }
    1530                                 }
    1531                         }
    1532                 }
    1533 
    1534                 void postvisit( const ast::UntypedTupleExpr * tupleExpr ) {
    1535                         std::vector< CandidateFinder > subCandidates =
    1536                                 selfFinder.findSubExprs( tupleExpr->exprs );
    1537                         std::vector< CandidateList > possibilities;
    1538                         combos( subCandidates.begin(), subCandidates.end(), back_inserter( possibilities ) );
    1539 
    1540                         for ( const CandidateList & subs : possibilities ) {
    1541                                 std::vector< ast::ptr< ast::Expr > > exprs;
    1542                                 exprs.reserve( subs.size() );
    1543                                 for ( const CandidateRef & sub : subs ) { exprs.emplace_back( sub->expr ); }
    1544 
    1545                                 ast::TypeEnvironment env;
    1546                                 ast::OpenVarSet open;
    1547                                 ast::AssertionSet need;
    1548                                 for ( const CandidateRef & sub : subs ) {
    1549                                         env.simpleCombine( sub->env );
    1550                                         mergeOpenVars( open, sub->open );
    1551                                         mergeAssertionSet( need, sub->need );
    1552                                 }
    1553 
    1554                                 addCandidate(
    1555                                         new ast::TupleExpr{ tupleExpr->location, std::move( exprs ) },
    1556                                         std::move( env ), std::move( open ), std::move( need ), sumCost( subs ) );
    1557                         }
    1558                 }
    1559 
    1560                 void postvisit( const ast::TupleExpr * tupleExpr ) {
    1561                         addCandidate( tupleExpr, tenv );
    1562                 }
    1563 
    1564                 void postvisit( const ast::TupleIndexExpr * tupleExpr ) {
    1565                         addCandidate( tupleExpr, tenv );
    1566                 }
    1567 
    1568                 void postvisit( const ast::TupleAssignExpr * tupleExpr ) {
    1569                         addCandidate( tupleExpr, tenv );
    1570                 }
    1571 
    1572                 void postvisit( const ast::UniqueExpr * unqExpr ) {
    1573                         CandidateFinder finder( context, tenv );
    1574                         finder.find( unqExpr->expr, ResolvMode::withAdjustment() );
    1575                         for ( CandidateRef & r : finder.candidates ) {
    1576                                 // ensure that the the id is passed on so that the expressions are "linked"
    1577                                 addCandidate( *r, new ast::UniqueExpr{ unqExpr->location, r->expr, unqExpr->id } );
    1578                         }
    1579                 }
    1580 
    1581                 void postvisit( const ast::StmtExpr * stmtExpr ) {
    1582                         addCandidate( resolveStmtExpr( stmtExpr, context ), tenv );
    1583                 }
    1584 
    1585                 void postvisit( const ast::UntypedInitExpr * initExpr ) {
    1586                         // handle each option like a cast
    1587                         CandidateList matches;
    1588                         PRINT(
    1589                                 std::cerr << "untyped init expr: " << initExpr << std::endl;
    1590                         )
    1591                         // O(n^2) checks of d-types with e-types
    1592                         for ( const ast::InitAlternative & initAlt : initExpr->initAlts ) {
    1593                                 // calculate target type
    1594                                 const ast::Type * toType = resolveTypeof( initAlt.type, context );
    1595                                 toType = adjustExprType( toType, tenv, symtab );
    1596                                 // The call to find must occur inside this loop, otherwise polymorphic return
    1597                                 // types are not bound to the initialization type, since return type variables are
    1598                                 // only open for the duration of resolving the UntypedExpr.
    1599                                 CandidateFinder finder( context, tenv, toType );
    1600                                 finder.find( initExpr->expr, ResolvMode::withAdjustment() );
    1601                                 for ( CandidateRef & cand : finder.candidates ) {
    1602                                         if(reason.code == NotFound) reason.code = NoMatch;
    1603 
    1604                                         ast::TypeEnvironment env{ cand->env };
    1605                                         ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
    1606                                         ast::OpenVarSet open{ cand->open };
    1607 
    1608                                         PRINT(
    1609                                                 std::cerr << "  @ " << toType << " " << initAlt.designation << std::endl;
    1610                                         )
    1611 
    1612                                         // It is possible that a cast can throw away some values in a multiply-valued
    1613                                         // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of
    1614                                         // the subexpression results that are cast directly. The candidate is invalid
    1615                                         // if it has fewer results than there are types to cast to.
    1616                                         int discardedValues = cand->expr->result->size() - toType->size();
    1617                                         if ( discardedValues < 0 ) continue;
    1618 
    1619                                         // unification run for side-effects
    1620                                         bool canUnify = unify( toType, cand->expr->result, env, need, have, open, symtab );
    1621                                         (void) canUnify;
    1622                                         Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(),
    1623                                                 symtab, env );
    1624                                         PRINT(
    1625                                                 Cost legacyCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(),
    1626                                                         symtab, env );
    1627                                                 std::cerr << "Considering initialization:";
    1628                                                 std::cerr << std::endl << "  FROM: " << cand->expr->result << std::endl;
    1629                                                 std::cerr << std::endl << "  TO: "   << toType             << std::endl;
    1630                                                 std::cerr << std::endl << "  Unification " << (canUnify ? "succeeded" : "failed");
    1631                                                 std::cerr << std::endl << "  Legacy cost " << legacyCost;
    1632                                                 std::cerr << std::endl << "  New cost " << thisCost;
    1633                                                 std::cerr << std::endl;
    1634                                         )
    1635                                         if ( thisCost != Cost::infinity ) {
    1636                                                 // count one safe conversion for each value that is thrown away
    1637                                                 thisCost.incSafe( discardedValues );
    1638                                                 CandidateRef newCand = std::make_shared<Candidate>(
    1639                                                         new ast::InitExpr{
    1640                                                                 initExpr->location, restructureCast( cand->expr, toType ),
    1641                                                                 initAlt.designation },
    1642                                                         std::move(env), std::move( open ), std::move( need ), cand->cost, thisCost );
    1643                                                 inferParameters( newCand, matches );
    1644                                         }
    1645                                 }
    1646 
    1647                         }
    1648 
    1649                         // select first on argument cost, then conversion cost
    1650                         CandidateList minArgCost = findMinCost( matches );
    1651                         promoteCvtCost( minArgCost );
    1652                         candidates = findMinCost( minArgCost );
    1653                 }
    1654 
    1655                 void postvisit( const ast::InitExpr * ) {
    1656                         assertf( false, "CandidateFinder should never see a resolved InitExpr." );
    1657                 }
    1658 
    1659                 void postvisit( const ast::DeletedExpr * ) {
    1660                         assertf( false, "CandidateFinder should never see a DeletedExpr." );
    1661                 }
    1662 
    1663                 void postvisit( const ast::GenericExpr * ) {
    1664                         assertf( false, "_Generic is not yet supported." );
    1665                 }
    1666         };
    1667 
    1668         // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder");
    1669         /// Prunes a list of candidates down to those that have the minimum conversion cost for a given
    1670         /// return type. Skips ambiguous candidates.
    1671 
    1672 } // anonymous namespace
    1673 
    1674 bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) {
    1675         struct PruneStruct {
    1676                 CandidateRef candidate;
    1677                 bool ambiguous;
    1678 
    1679                 PruneStruct() = default;
    1680                 PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {}
    1681         };
    1682 
    1683         // find lowest-cost candidate for each type
    1684         std::unordered_map< std::string, PruneStruct > selected;
    1685         // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found
    1686         std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;});
    1687         for ( CandidateRef & candidate : candidates ) {
    1688                 std::string mangleName;
    1689                 {
    1690                         ast::ptr< ast::Type > newType = candidate->expr->result;
    1691                         assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get());
    1692                         candidate->env.apply( newType );
    1693                         mangleName = Mangle::mangle( newType );
    1694                 }
    1695 
    1696                 auto found = selected.find( mangleName );
    1697                 if (found != selected.end() && found->second.candidate->cost < candidate->cost) {
    1698                         PRINT(
    1699                                 std::cerr << "cost " << candidate->cost << " loses to "
    1700                                         << found->second.candidate->cost << std::endl;
    1701                         )
    1702                         continue;
    1703                 }
    1704 
    1705                 // xxx - when do satisfyAssertions produce more than 1 result?
    1706                 // this should only happen when initial result type contains
    1707                 // unbound type parameters, then it should never be pruned by
    1708                 // the previous step, since renameTyVars guarantees the mangled name
    1709                 // is unique.
    1710                 CandidateList satisfied;
    1711                 bool needRecomputeKey = false;
    1712                 if (candidate->need.empty()) {
    1713                         satisfied.emplace_back(candidate);
    1714                 }
    1715                 else {
    1716                         satisfyAssertions(candidate, context.symtab, satisfied, errors);
    1717                         needRecomputeKey = true;
    1718                 }
    1719 
    1720                 for (auto & newCand : satisfied) {
    1721                         // recomputes type key, if satisfyAssertions changed it
    1722                         if (needRecomputeKey)
    1723                         {
    1724                                 ast::ptr< ast::Type > newType = newCand->expr->result;
    1725                                 assertf(newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get());
    1726                                 newCand->env.apply( newType );
    1727                                 mangleName = Mangle::mangle( newType );
    1728                         }
    1729                         auto found = selected.find( mangleName );
    1730                         if ( found != selected.end() ) {
    1731                                 if ( newCand->cost < found->second.candidate->cost ) {
    1732                                         PRINT(
    1733                                                 std::cerr << "cost " << newCand->cost << " beats "
    1734                                                         << found->second.candidate->cost << std::endl;
    1735                                         )
    1736 
    1737                                         found->second = PruneStruct{ newCand };
    1738                                 } else if ( newCand->cost == found->second.candidate->cost ) {
    1739                                         // if one of the candidates contains a deleted identifier, can pick the other,
    1740                                         // since deleted expressions should not be ambiguous if there is another option
    1741                                         // that is at least as good
    1742                                         if ( findDeletedExpr( newCand->expr ) ) {
    1743                                                 // do nothing
    1744                                                 PRINT( std::cerr << "candidate is deleted" << std::endl; )
    1745                                         } else if ( findDeletedExpr( found->second.candidate->expr ) ) {
    1746                                                 PRINT( std::cerr << "current is deleted" << std::endl; )
    1747                                                 found->second = PruneStruct{ newCand };
    1748                                         } else {
    1749                                                 PRINT( std::cerr << "marking ambiguous" << std::endl; )
    1750                                                 found->second.ambiguous = true;
    1751                                         }
    1752                                 } else {
    1753                                         // xxx - can satisfyAssertions increase the cost?
    1754                                         PRINT(
    1755                                                 std::cerr << "cost " << newCand->cost << " loses to "
    1756                                                         << found->second.candidate->cost << std::endl;
    1757                                         )
    1758                                 }
    1759                         } else {
    1760                                 selected.emplace_hint( found, mangleName, newCand );
    1761                         }
    1762                 }
    1763         }
    1764 
    1765         // report unambiguous min-cost candidates
    1766         // CandidateList out;
    1767         for ( auto & target : selected ) {
    1768                 if ( target.second.ambiguous ) continue;
    1769 
    1770                 CandidateRef cand = target.second.candidate;
    1771 
    1772                 ast::ptr< ast::Type > newResult = cand->expr->result;
    1773                 cand->env.applyFree( newResult );
    1774                 cand->expr = ast::mutate_field(
    1775                         cand->expr.get(), &ast::Expr::result, std::move( newResult ) );
    1776 
    1777                 out.emplace_back( cand );
    1778         }
    1779         // if everything is lost in satisfyAssertions, report the error
    1780         return !selected.empty();
    1781 }
    1782 
    1783 void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) {
    1784         // Find alternatives for expression
    1785         ast::Pass<Finder> finder{ *this };
    1786         expr->accept( finder );
    1787 
    1788         if ( mode.failFast && candidates.empty() ) {
    1789                 switch(finder.core.reason.code) {
    1790                 case Finder::NotFound:
    1791                         { SemanticError( expr, "No alternatives for expression " ); break; }
    1792                 case Finder::NoMatch:
    1793                         { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; }
    1794                 case Finder::ArgsToFew:
    1795                 case Finder::ArgsToMany:
    1796                 case Finder::RetsToFew:
    1797                 case Finder::RetsToMany:
    1798                 case Finder::NoReason:
    1799                 default:
    1800                         { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); }
    1801                 }
    1802         }
    1803 
    1804         /*
    1805         if ( mode.satisfyAssns || mode.prune ) {
    1806                 // trim candidates to just those where the assertions are satisfiable
    1807                 // - necessary pre-requisite to pruning
    1808                 CandidateList satisfied;
    1809                 std::vector< std::string > errors;
    1810                 for ( CandidateRef & candidate : candidates ) {
    1811                         satisfyAssertions( candidate, localSyms, satisfied, errors );
    1812                 }
    1813 
    1814                 // fail early if none such
    1815                 if ( mode.failFast && satisfied.empty() ) {
    1816                         std::ostringstream stream;
    1817                         stream << "No alternatives with satisfiable assertions for " << expr << "\n";
    1818                         for ( const auto& err : errors ) {
    1819                                 stream << err;
    1820                         }
    1821                         SemanticError( expr->location, stream.str() );
    1822                 }
    1823 
    1824                 // reset candidates
    1825                 candidates = move( satisfied );
    1826         }
    1827         */
    1828 
    1829         if ( mode.prune ) {
    1830                 // trim candidates to single best one
    1831                 PRINT(
    1832                         std::cerr << "alternatives before prune:" << std::endl;
    1833                         print( std::cerr, candidates );
    1834                 )
    1835 
    1836                 CandidateList pruned;
    1837                 std::vector<std::string> errors;
    1838                 bool found = pruneCandidates( candidates, pruned, errors );
    1839 
    1840                 if ( mode.failFast && pruned.empty() ) {
    1841                         std::ostringstream stream;
    1842                         if (found) {
    1843                                 CandidateList winners = findMinCost( candidates );
    1844                                 stream << "Cannot choose between " << winners.size() << " alternatives for "
    1845                                         "expression\n";
    1846                                 ast::print( stream, expr );
    1847                                 stream << " Alternatives are:\n";
    1848                                 print( stream, winners, 1 );
    1849                                 SemanticError( expr->location, stream.str() );
    1850                         }
    1851                         else {
    1852                                 stream << "No alternatives with satisfiable assertions for " << expr << "\n";
    1853                                 for ( const auto& err : errors ) {
    1854                                         stream << err;
    1855                                 }
    1856                                 SemanticError( expr->location, stream.str() );
    1857                         }
    1858                 }
    1859 
    1860                 auto oldsize = candidates.size();
    1861                 candidates = std::move( pruned );
    1862 
    1863                 PRINT(
    1864                         std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl;
    1865                 )
    1866                 PRINT(
    1867                         std::cerr << "there are " << candidates.size() << " alternatives after elimination"
    1868                                 << std::endl;
    1869                 )
    1870         }
    1871 
    1872         // adjust types after pruning so that types substituted by pruneAlternatives are correctly
    1873         // adjusted
    1874         if ( mode.adjust ) {
    1875                 for ( CandidateRef & r : candidates ) {
    1876                         r->expr = ast::mutate_field(
    1877                                 r->expr.get(), &ast::Expr::result,
    1878                                 adjustExprType( r->expr->result, r->env, context.symtab ) );
    1879                 }
    1880         }
    1881 
    1882         // Central location to handle gcc extension keyword, etc. for all expressions
    1883         for ( CandidateRef & r : candidates ) {
    1884                 if ( r->expr->extension != expr->extension ) {
    1885                         r->expr.get_and_mutate()->extension = expr->extension;
    1886                 }
    1887         }
    1888 }
    1889 
    1890 std::vector< CandidateFinder > CandidateFinder::findSubExprs(
    1891         const std::vector< ast::ptr< ast::Expr > > & xs
    1892 ) {
    1893         std::vector< CandidateFinder > out;
    1894 
    1895         for ( const auto & x : xs ) {
    1896                 out.emplace_back( context, env );
    1897                 out.back().find( x, ResolvMode::withAdjustment() );
    1898 
    1899                 PRINT(
    1900                         std::cerr << "findSubExprs" << std::endl;
    1901                         print( std::cerr, out.back().candidates );
    1902                 )
    1903         }
    1904 
    1905         return out;
    1906 }
    1907 
    19081970} // namespace ResolvExpr
    19091971
  • src/ResolvExpr/CurrentObject.cc

    ra50fdfb r6e1e2d0  
    99// Author           : Rob Schluntz
    1010// Created On       : Tue Jun 13 15:28:32 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jul  1 09:16:01 2022
    13 // Update Count     : 15
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Apr 10  9:40:00 2023
     13// Update Count     : 18
    1414//
    1515
     
    593593
    594594namespace ast {
     595        /// Iterates members of a type by initializer.
     596        class MemberIterator {
     597        public:
     598                virtual ~MemberIterator() {}
     599
     600                /// Internal set position based on iterator ranges.
     601                virtual void setPosition(
     602                        std::deque< ptr< Expr > >::const_iterator it,
     603                        std::deque< ptr< Expr > >::const_iterator end ) = 0;
     604
     605                /// Walks the current object using the given designators as a guide.
     606                void setPosition( const std::deque< ptr< Expr > > & designators ) {
     607                        setPosition( designators.begin(), designators.end() );
     608                }
     609
     610                /// Retrieve the list of possible (Type,Designation) pairs for the
     611                /// current position in the current object.
     612                virtual std::deque< InitAlternative > operator* () const = 0;
     613
     614                /// True if the iterator is not currently at the end.
     615                virtual operator bool() const = 0;
     616
     617                /// Moves the iterator by one member in the current object.
     618                virtual MemberIterator & bigStep() = 0;
     619
     620                /// Moves the iterator by one member in the current subobject.
     621                virtual MemberIterator & smallStep() = 0;
     622
     623                /// The type of the current object.
     624                virtual const Type * getType() = 0;
     625
     626                /// The type of the current subobject.
     627                virtual const Type * getNext() = 0;
     628
     629                /// Helper for operator*; aggregates must add designator to each init
     630                /// alternative, but adding designators in operator* creates duplicates.
     631                virtual std::deque< InitAlternative > first() const = 0;
     632        };
     633
    595634        /// create a new MemberIterator that traverses a type correctly
    596635        MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type );
     
    632671        };
    633672
    634         /// Iterates array types
    635         class ArrayIterator final : public MemberIterator {
     673        /// Iterates over an indexed type:
     674        class IndexIterator : public MemberIterator {
     675        protected:
    636676                CodeLocation location;
    637                 const ArrayType * array = nullptr;
    638                 const Type * base = nullptr;
    639677                size_t index = 0;
    640678                size_t size = 0;
    641                 std::unique_ptr< MemberIterator > memberIter;
    642 
    643                 void setSize( const Expr * expr ) {
    644                         auto res = eval( expr );
    645                         if ( ! res.second ) {
    646                                 SemanticError( location, toString( "Array designator must be a constant expression: ", expr ) );
    647                         }
    648                         size = res.first;
    649                 }
    650 
    651         public:
    652                 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) : location( loc ), array( at ), base( at->base ) {
    653                         PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
    654                         memberIter.reset( createMemberIterator( loc, base ) );
    655                         if ( at->isVarLen ) {
    656                                 SemanticError( location, at, "VLA initialization does not support @=: " );
    657                         }
    658                         setSize( at->dimension );
    659                 }
     679                std::unique_ptr<MemberIterator> memberIter;
     680        public:
     681                IndexIterator( const CodeLocation & loc, size_t size ) :
     682                        location( loc ), size( size )
     683                {}
    660684
    661685                void setPosition( const Expr * expr ) {
     
    666690                        auto arg = eval( expr );
    667691                        index = arg.first;
    668                         return;
    669692
    670693                        // if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) {
     
    684707
    685708                void setPosition(
    686                         std::deque< ptr< Expr > >::const_iterator begin,
    687                         std::deque< ptr< Expr > >::const_iterator end
     709                        std::deque<ast::ptr<ast::Expr>>::const_iterator begin,
     710                        std::deque<ast::ptr<ast::Expr>>::const_iterator end
    688711                ) override {
    689712                        if ( begin == end ) return;
     
    696719
    697720                operator bool() const override { return index < size; }
     721        };
     722
     723        /// Iterates over the members of array types:
     724        class ArrayIterator final : public IndexIterator {
     725                const ArrayType * array = nullptr;
     726                const Type * base = nullptr;
     727
     728                size_t getSize( const Expr * expr ) {
     729                        auto res = eval( expr );
     730                        if ( !res.second ) {
     731                                SemanticError( location, toString( "Array designator must be a constant expression: ", expr ) );
     732                        }
     733                        return res.first;
     734                }
     735
     736        public:
     737                ArrayIterator( const CodeLocation & loc, const ArrayType * at ) :
     738                                IndexIterator( loc, getSize( at->dimension) ),
     739                                array( at ), base( at->base ) {
     740                        PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
     741                        memberIter.reset( createMemberIterator( loc, base ) );
     742                        if ( at->isVarLen ) {
     743                                SemanticError( location, at, "VLA initialization does not support @=: " );
     744                        }
     745                }
    698746
    699747                ArrayIterator & bigStep() override {
     
    834882
    835883                const Type * getNext() final {
    836                         return ( memberIter && *memberIter ) ? memberIter->getType() : nullptr;
     884                        bool hasMember = memberIter && *memberIter;
     885                        return hasMember ? memberIter->getType() : nullptr;
    837886                }
    838887
     
    898947        };
    899948
    900         class TupleIterator final : public AggregateIterator {
    901         public:
    902                 TupleIterator( const CodeLocation & loc, const TupleType * inst )
    903                 : AggregateIterator(
    904                         loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members
    905                 ) {}
    906 
    907                 operator bool() const override {
    908                         return curMember != members.end() || (memberIter && *memberIter);
     949        /// Iterates across the positions in a tuple:
     950        class TupleIterator final : public IndexIterator {
     951                ast::TupleType const * const tuple;
     952
     953                const ast::Type * typeAtIndex() const {
     954                        assert( index < size );
     955                        return tuple->types[ index ].get();
     956                }
     957
     958        public:
     959                TupleIterator( const CodeLocation & loc, const TupleType * type )
     960                : IndexIterator( loc, type->size() ), tuple( type ) {
     961                        PRINT( std::cerr << "Creating tuple iterator: " << type << std::endl; )
     962                        memberIter.reset( createMemberIterator( loc, typeAtIndex() ) );
    909963                }
    910964
    911965                TupleIterator & bigStep() override {
    912                         PRINT( std::cerr << "bigStep in " << kind << std::endl; )
    913                         atbegin = false;
    914                         memberIter = nullptr;
    915                         curType = nullptr;
    916                         while ( curMember != members.end() ) {
    917                                 ++curMember;
    918                                 if ( init() ) return *this;
    919                         }
     966                        ++index;
     967                        memberIter.reset( index < size ?
     968                                createMemberIterator( location, typeAtIndex() ) : nullptr );
    920969                        return *this;
     970                }
     971
     972                TupleIterator & smallStep() override {
     973                        if ( memberIter ) {
     974                                PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; )
     975                                memberIter->smallStep();
     976                                if ( !memberIter ) {
     977                                        PRINT( std::cerr << "has valid member iter" << std::endl; )
     978                                        return *this;
     979                                }
     980                        }
     981                        return bigStep();
     982                }
     983
     984                const ast::Type * getType() override {
     985                        return tuple;
     986                }
     987
     988                const ast::Type * getNext() override {
     989                        bool hasMember = memberIter && *memberIter;
     990                        return hasMember ? memberIter->getType() : nullptr;
     991                }
     992
     993                std::deque< InitAlternative > first() const override {
     994                        PRINT( std::cerr << "first in TupleIterator (" << index << "/" << size << ")" << std::endl; )
     995                        if ( memberIter && *memberIter ) {
     996                                std::deque< InitAlternative > ret = memberIter->first();
     997                                for ( InitAlternative & alt : ret ) {
     998                                        alt.designation.get_and_mutate()->designators.emplace_front(
     999                                                ConstantExpr::from_ulong( location, index ) );
     1000                                }
     1001                                return ret;
     1002                        }
     1003                        return {};
    9211004                }
    9221005        };
  • src/ResolvExpr/CurrentObject.h

    ra50fdfb r6e1e2d0  
    99// Author           : Rob Schluntz
    1010// Created On       : Thu Jun  8 11:07:25 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:36:48 2017
    13 // Update Count     : 3
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu Apr  6 16:14:00 2023
     13// Update Count     : 4
    1414//
    1515
     
    6565
    6666        /// 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         };
     67        class MemberIterator;
    10468
    10569        /// Builds initializer lists in resolution
  • src/ResolvExpr/ExplodedArg.hpp

    ra50fdfb r6e1e2d0  
    3535        ExplodedArg() : env(), cost( Cost::zero ), exprs() {}
    3636        ExplodedArg( const Candidate & arg, const ast::SymbolTable & symtab );
    37        
     37
    3838        ExplodedArg( ExplodedArg && ) = default;
    3939        ExplodedArg & operator= ( ExplodedArg && ) = default;
  • src/SymTab/Autogen.cc

    ra50fdfb r6e1e2d0  
    1010// Created On       : Thu Mar 03 15:45:56 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Apr 27 14:39:06 2018
    13 // Update Count     : 63
     12// Last Modified On : Fri Apr 14 15:03:00 2023
     13// Update Count     : 64
    1414//
    1515
     
    211211        }
    212212
    213         bool isUnnamedBitfield( const ast::ObjectDecl * obj ) {
    214                 return obj && obj->name.empty() && obj->bitfieldWidth;
    215         }
    216 
    217213        /// inserts a forward declaration for functionDecl into declsToAdd
    218214        void addForwardDecl( FunctionDecl * functionDecl, std::list< Declaration * > & declsToAdd ) {
     
    234230        }
    235231
    236         // shallow copy the pointer list for return
    237         std::vector<ast::ptr<ast::TypeDecl>> getGenericParams (const ast::Type * t) {
    238                 if (auto structInst = dynamic_cast<const ast::StructInstType*>(t)) {
    239                         return structInst->base->params;
    240                 }
    241                 if (auto unionInst = dynamic_cast<const ast::UnionInstType*>(t)) {
    242                         return unionInst->base->params;
    243                 }
    244                 return {};
    245         }
    246 
    247232        /// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *)
    248233        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic ) {
     
    256241                ftype->parameters.push_back( dstParam );
    257242                return ftype;
    258         }
    259 
    260         /// Given type T, generate type of default ctor/dtor, i.e. function type void (*) (T &).
    261         ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic) {
    262                 std::vector<ast::ptr<ast::TypeDecl>> typeParams;
    263                 if (maybePolymorphic) typeParams = getGenericParams(paramType);
    264                 auto dstParam = new ast::ObjectDecl(loc, "_dst", new ast::ReferenceType(paramType), nullptr, {}, ast::Linkage::Cforall);
    265                 return new ast::FunctionDecl(loc, fname, std::move(typeParams), {dstParam}, {}, new ast::CompoundStmt(loc), {}, ast::Linkage::Cforall);
    266243        }
    267244
  • src/SymTab/Autogen.h

    ra50fdfb r6e1e2d0  
    99// Author           : Rob Schluntz
    1010// Created On       : Sun May 17 21:53:34 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 16:38:06 2019
    13 // Update Count     : 16
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Apr 14 15:06:00 2023
     13// Update Count     : 17
    1414//
    1515
     
    4545        /// returns true if obj's name is the empty string and it has a bitfield width
    4646        bool isUnnamedBitfield( ObjectDecl * obj );
    47         bool isUnnamedBitfield( const ast::ObjectDecl * obj );
    4847
    4948        /// generate the type of an assignment function for paramType.
     
    5554        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic = true );
    5655
    57         ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic = true);
    58 
    5956        /// generate the type of a copy constructor for paramType.
    6057        /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic
     
    6764        template< typename OutputIterator >
    6865        Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast = nullptr, bool forward = true );
    69 
    70         template< typename OutIter >
    71         ast::ptr< ast::Stmt > genCall(
    72                 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
    73                 const CodeLocation & loc, const std::string & fname, OutIter && out,
    74                 const ast::Type * type, const ast::Type * addCast, LoopDirection forward = LoopForward );
    7566
    7667        /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Should only be called with non-array types.
     
    121112
    122113                *out++ = new ExprStmt( fExpr );
    123 
    124                 srcParam.clearArrayIndices();
    125 
    126                 return listInit;
    127         }
    128 
    129         /// inserts into out a generated call expression to function fname with arguments dstParam and
    130         /// srcParam. Should only be called with non-array types.
    131         /// optionally returns a statement which must be inserted prior to the containing loop, if
    132         /// there is one
    133         template< typename OutIter >
    134         ast::ptr< ast::Stmt > genScalarCall(
    135                 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
    136                 const CodeLocation & loc, std::string fname, OutIter && out, const ast::Type * type,
    137                 const ast::Type * addCast = nullptr
    138         ) {
    139                 bool isReferenceCtorDtor = false;
    140                 if ( dynamic_cast< const ast::ReferenceType * >( type ) && CodeGen::isCtorDtor( fname ) ) {
    141                         // reference constructors are essentially application of the rebind operator.
    142                         // apply & to both arguments, do not need a cast
    143                         fname = "?=?";
    144                         dstParam = new ast::AddressExpr{ dstParam };
    145                         addCast = nullptr;
    146                         isReferenceCtorDtor = true;
    147                 }
    148 
    149                 // want to be able to generate assignment, ctor, and dtor generically, so fname is one of
    150                 // "?=?", "?{}", or "^?{}"
    151                 ast::UntypedExpr * fExpr = new ast::UntypedExpr{ loc, new ast::NameExpr{ loc, fname } };
    152 
    153                 if ( addCast ) {
    154                         // cast to T& with qualifiers removed, so that qualified objects can be constructed and
    155                         // destructed with the same functions as non-qualified objects. Unfortunately, lvalue
    156                         // is considered a qualifier - for AddressExpr to resolve, its argument must have an
    157                         // lvalue-qualified type, so remove all qualifiers except lvalue.
    158                         // xxx -- old code actually removed lvalue too...
    159                         ast::ptr< ast::Type > guard = addCast;  // prevent castType from mutating addCast
    160                         ast::ptr< ast::Type > castType = addCast;
    161                         ast::remove_qualifiers(
    162                                 castType,
    163                                 ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Atomic );
    164                         dstParam = new ast::CastExpr{ dstParam, new ast::ReferenceType{ castType } };
    165                 }
    166                 fExpr->args.emplace_back( dstParam );
    167 
    168                 ast::ptr<ast::Stmt> listInit = srcParam.buildListInit( fExpr );
    169 
    170                 // fetch next set of arguments
    171                 ++srcParam;
    172 
    173                 // return if adding reference fails -- will happen on default ctor and dtor
    174                 if ( isReferenceCtorDtor && ! srcParam.addReference() ) return listInit;
    175 
    176                 std::vector< ast::ptr< ast::Expr > > args = *srcParam;
    177                 splice( fExpr->args, args );
    178 
    179                 *out++ = new ast::ExprStmt{ loc, fExpr };
    180114
    181115                srcParam.clearArrayIndices();
     
    248182        }
    249183
    250         /// Store in out a loop which calls fname on each element of the array with srcParam and
    251         /// dstParam as arguments. If forward is true, loop goes from 0 to N-1, else N-1 to 0
    252         template< typename OutIter >
    253         void genArrayCall(
    254                 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
    255                 const CodeLocation & loc, const std::string & fname, OutIter && out,
    256                 const ast::ArrayType * array, const ast::Type * addCast = nullptr,
    257                 LoopDirection forward = LoopForward
    258         ) {
    259                 static UniqueName indexName( "_index" );
    260 
    261                 // for a flexible array member nothing is done -- user must define own assignment
    262                 if ( ! array->dimension ) return;
    263 
    264                 if ( addCast ) {
    265                         // peel off array layer from cast
    266                         addCast = strict_dynamic_cast< const ast::ArrayType * >( addCast )->base;
    267                 }
    268 
    269                 ast::ptr< ast::Expr > begin, end;
    270                 std::string cmp, update;
    271 
    272                 if ( forward ) {
    273                         // generate: for ( int i = 0; i < N; ++i )
    274                         begin = ast::ConstantExpr::from_int( loc, 0 );
    275                         end = array->dimension;
    276                         cmp = "?<?";
    277                         update = "++?";
    278                 } else {
    279                         // generate: for ( int i = N-1; i >= 0; --i )
    280                         begin = ast::UntypedExpr::createCall( loc, "?-?",
    281                                 { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } );
    282                         end = ast::ConstantExpr::from_int( loc, 0 );
    283                         cmp = "?>=?";
    284                         update = "--?";
    285                 }
    286 
    287                 ast::ptr< ast::DeclWithType > index = new ast::ObjectDecl{
    288                         loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt },
    289                         new ast::SingleInit{ loc, begin } };
    290                 ast::ptr< ast::Expr > indexVar = new ast::VariableExpr{ loc, index };
    291 
    292                 ast::ptr< ast::Expr > cond = ast::UntypedExpr::createCall(
    293                         loc, cmp, { indexVar, end } );
    294 
    295                 ast::ptr< ast::Expr > inc = ast::UntypedExpr::createCall(
    296                         loc, update, { indexVar } );
    297 
    298                 ast::ptr< ast::Expr > dstIndex = ast::UntypedExpr::createCall(
    299                         loc, "?[?]", { dstParam, indexVar } );
    300 
    301                 // srcParam must keep track of the array indices to build the source parameter and/or
    302                 // array list initializer
    303                 srcParam.addArrayIndex( indexVar, array->dimension );
    304 
    305                 // for stmt's body, eventually containing call
    306                 ast::CompoundStmt * body = new ast::CompoundStmt{ loc };
    307                 ast::ptr< ast::Stmt > listInit = genCall(
    308                         srcParam, dstIndex, loc, fname, std::back_inserter( body->kids ), array->base, addCast,
    309                         forward );
    310 
    311                 // block containing the stmt and index variable
    312                 ast::CompoundStmt * block = new ast::CompoundStmt{ loc };
    313                 block->push_back( new ast::DeclStmt{ loc, index } );
    314                 if ( listInit ) { block->push_back( listInit ); }
    315                 block->push_back( new ast::ForStmt{ loc, {}, cond, inc, body } );
    316 
    317                 *out++ = block;
    318         }
    319 
    320184        template< typename OutputIterator >
    321185        Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast, bool forward ) {
     
    325189                } else {
    326190                        return genScalarCall( srcParam, dstParam, fname, out, type, addCast );
    327                 }
    328         }
    329 
    330         template< typename OutIter >
    331         ast::ptr< ast::Stmt > genCall(
    332                 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
    333                 const CodeLocation & loc, const std::string & fname, OutIter && out,
    334                 const ast::Type * type, const ast::Type * addCast, LoopDirection forward
    335         ) {
    336                 if ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
    337                         genArrayCall(
    338                                 srcParam, dstParam, loc, fname, std::forward< OutIter >(out), at, addCast,
    339                                 forward );
    340                         return {};
    341                 } else {
    342                         return genScalarCall(
    343                                 srcParam, dstParam, loc, fname, std::forward< OutIter >( out ), type, addCast );
    344191                }
    345192        }
     
    379226        }
    380227
    381         static inline ast::ptr< ast::Stmt > genImplicitCall(
    382                 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
    383                 const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj,
    384                 LoopDirection forward = LoopForward
    385         ) {
    386                 // unnamed bit fields are not copied as they cannot be accessed
    387                 if ( isUnnamedBitfield( obj ) ) return {};
    388 
    389                 ast::ptr< ast::Type > addCast;
    390                 if ( (fname == "?{}" || fname == "^?{}") && ( ! obj || ( obj && ! obj->bitfieldWidth ) ) ) {
    391                         assert( dstParam->result );
    392                         addCast = dstParam->result;
    393                 }
    394 
    395                 std::vector< ast::ptr< ast::Stmt > > stmts;
    396                 genCall(
    397                         srcParam, dstParam, loc, fname, back_inserter( stmts ), obj->type, addCast, forward );
    398 
    399                 if ( stmts.empty() ) {
    400                         return {};
    401                 } else if ( stmts.size() == 1 ) {
    402                         const ast::Stmt * callStmt = stmts.front();
    403                         if ( addCast ) {
    404                                 // implicitly generated ctor/dtor calls should be wrapped so that later passes are
    405                                 // aware they were generated.
    406                                 callStmt = new ast::ImplicitCtorDtorStmt{ callStmt->location, callStmt };
    407                         }
    408                         return callStmt;
    409                 } else {
    410                         assert( false );
    411                         return {};
    412                 }
    413         }
    414228} // namespace SymTab
    415229
  • src/SymTab/module.mk

    ra50fdfb r6e1e2d0  
    2020        SymTab/FixFunction.cc \
    2121        SymTab/FixFunction.h \
     22        SymTab/GenImplicitCall.cpp \
     23        SymTab/GenImplicitCall.hpp \
    2224        SymTab/Indexer.cc \
    2325        SymTab/Indexer.h \
  • src/Validate/Autogen.cpp

    ra50fdfb r6e1e2d0  
    3939#include "InitTweak/GenInit.h"     // for fixReturnStatements
    4040#include "InitTweak/InitTweak.h"   // for isAssignment, isCopyConstructor
     41#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    4142#include "SymTab/Mangler.h"        // for Mangler
    4243#include "CompilationState.h"
     
    423424        for ( unsigned int index = 0 ; index < fields ; ++index ) {
    424425                auto member = aggr->members[index].strict_as<ast::DeclWithType>();
    425                 if ( SymTab::isUnnamedBitfield(
     426                if ( ast::isUnnamedBitfield(
    426427                                dynamic_cast<const ast::ObjectDecl *>( member ) ) ) {
    427428                        if ( index == fields - 1 ) {
     
    599600                // Not sure why it could be null.
    600601                // Don't make a function for a parameter that is an unnamed bitfield.
    601                 if ( nullptr == field || SymTab::isUnnamedBitfield( field ) ) {
     602                if ( nullptr == field || ast::isUnnamedBitfield( field ) ) {
    602603                        continue;
    603604                // Matching Parameter: Initialize the field by copy.
  • src/main.cc

    ra50fdfb r6e1e2d0  
    99// Author           : Peter Buhr and Rob Schluntz
    1010// Created On       : Fri May 15 23:12:02 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Feb 16 10:08:00 2023
    13 // Update Count     : 680
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Apr 10 21:12:17 2023
     13// Update Count     : 682
    1414//
    1515
     
    3232
    3333#include "AST/Convert.hpp"
     34#include "AST/Util.hpp"                     // for checkInvariants
    3435#include "CompilationState.h"
    3536#include "../config.h"                      // for CFA_LIBDIR
     
    102103}
    103104
    104 #define PASS( name, pass )                  \
     105// Helpers for checkInvariant:
     106void checkInvariants( std::list< Declaration * > & ) {}
     107using ast::checkInvariants;
     108
     109#define PASS( name, pass, unit, ... )       \
    105110        if ( errorp ) { cerr << name << endl; } \
    106111        NewPass(name);                          \
    107112        Stats::Time::StartBlock(name);          \
    108         pass;                                   \
    109         Stats::Time::StopBlock();
     113        pass(unit,##__VA_ARGS__);               \
     114        Stats::Time::StopBlock();               \
     115        if ( invariant ) {                      \
     116                checkInvariants(unit);              \
     117        }
     118
     119#define DUMP( cond, unit )                  \
     120        if ( cond ) {                           \
     121                dump(unit);                         \
     122                return EXIT_SUCCESS;                \
     123        }
    110124
    111125static bool waiting_for_gdb = false;                                    // flag to set cfa-cpp to wait for gdb on start
     
    298312                transUnit = buildUnit();
    299313
    300                 if ( astp ) {
    301                         dump( std::move( transUnit ) );
    302                         return EXIT_SUCCESS;
    303                 } // if
     314                DUMP( astp, std::move( transUnit ) );
    304315
    305316                Stats::Time::StopBlock();
     
    310321                }
    311322
    312                 PASS( "Hoist Type Decls", Validate::hoistTypeDecls( transUnit ) );
    313                 // Hoist Type Decls pulls some declarations out of contexts where
    314                 // locations are not tracked. Perhaps they should be, but for now
    315                 // the full fill solves it.
    316                 forceFillCodeLocations( transUnit );
    317 
    318                 PASS( "Translate Exception Declarations", ControlStruct::translateExcept( transUnit ) );
    319                 if ( exdeclp ) {
    320                         dump( std::move( transUnit ) );
    321                         return EXIT_SUCCESS;
    322                 }
    323 
    324                 PASS( "Verify Ctor, Dtor & Assign", Validate::verifyCtorDtorAssign( transUnit ) );
    325                 PASS( "Replace Typedefs", Validate::replaceTypedef( transUnit ) );
    326                 PASS( "Fix Return Types", Validate::fixReturnTypes( transUnit ) );
    327                 PASS( "Enum and Pointer Decay", Validate::decayEnumsAndPointers( transUnit ) );
    328 
    329                 PASS( "Link Reference To Types", Validate::linkReferenceToTypes( transUnit ) );
    330 
    331                 PASS( "Fix Qualified Types", Validate::fixQualifiedTypes( transUnit ) );
    332                 PASS( "Hoist Struct", Validate::hoistStruct( transUnit ) );
    333                 PASS( "Eliminate Typedef", Validate::eliminateTypedef( transUnit ) );
    334                 PASS( "Validate Generic Parameters", Validate::fillGenericParameters( transUnit ) );
    335                 PASS( "Translate Dimensions", Validate::translateDimensionParameters( transUnit ) );
    336                 PASS( "Check Function Returns", Validate::checkReturnStatements( transUnit ) );
    337                 PASS( "Fix Return Statements", InitTweak::fixReturnStatements( transUnit ) );
    338                 PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords( transUnit ) );
    339                 PASS( "Forall Pointer Decay", Validate::decayForallPointers( transUnit ) );
    340         PASS( "Implement Waituntil", Concurrency::generateWaitUntil( transUnit ) );
    341                 PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls( transUnit ) );
    342 
    343                 PASS( "Generate Autogen Routines", Validate::autogenerateRoutines( transUnit ) );
    344 
    345                 PASS( "Implement Actors", Concurrency::implementActors( transUnit ) );
    346         PASS( "Implement Virtual Destructors", Virtual::implementVirtDtors(transUnit) );
    347                 PASS( "Implement Mutex", Concurrency::implementMutex( transUnit ) );
    348                 PASS( "Implement Thread Start", Concurrency::implementThreadStarter( transUnit ) );
    349                 PASS( "Compound Literal", Validate::handleCompoundLiterals( transUnit ) );
    350                 PASS( "Set Length From Initializer", Validate::setLengthFromInitializer( transUnit ) );
    351                 PASS( "Find Global Decls", Validate::findGlobalDecls( transUnit ) );
    352                 PASS( "Fix Label Address", Validate::fixLabelAddresses( transUnit ) );
     323                PASS( "Hoist Type Decls", Validate::hoistTypeDecls, transUnit );
     324
     325                PASS( "Translate Exception Declarations", ControlStruct::translateExcept, transUnit );
     326                DUMP( exdeclp, std::move( transUnit ) );
     327                PASS( "Verify Ctor, Dtor & Assign", Validate::verifyCtorDtorAssign, transUnit );
     328                PASS( "Replace Typedefs", Validate::replaceTypedef, transUnit );
     329                PASS( "Fix Return Types", Validate::fixReturnTypes, transUnit );
     330                PASS( "Enum and Pointer Decay", Validate::decayEnumsAndPointers, transUnit );
     331
     332                PASS( "Link Reference To Types", Validate::linkReferenceToTypes, transUnit );
     333
     334                PASS( "Fix Qualified Types", Validate::fixQualifiedTypes, transUnit );
     335                PASS( "Hoist Struct", Validate::hoistStruct, transUnit );
     336                PASS( "Eliminate Typedef", Validate::eliminateTypedef, transUnit );
     337                PASS( "Validate Generic Parameters", Validate::fillGenericParameters, transUnit );
     338                PASS( "Translate Dimensions", Validate::translateDimensionParameters, transUnit );
     339                PASS( "Check Function Returns", Validate::checkReturnStatements, transUnit );
     340                PASS( "Fix Return Statements", InitTweak::fixReturnStatements, transUnit );
     341                PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords, transUnit );
     342                PASS( "Forall Pointer Decay", Validate::decayForallPointers, transUnit );
     343        PASS( "Implement Waituntil", Concurrency::generateWaitUntil, transUnit  );
     344                PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls, transUnit );
     345
     346                PASS( "Generate Autogen Routines", Validate::autogenerateRoutines, transUnit );
     347
     348                PASS( "Implement Actors", Concurrency::implementActors, transUnit );
     349                PASS( "Implement Virtual Destructors", Virtual::implementVirtDtors, transUnit );
     350                PASS( "Implement Mutex", Concurrency::implementMutex, transUnit );
     351                PASS( "Implement Thread Start", Concurrency::implementThreadStarter, transUnit );
     352                PASS( "Compound Literal", Validate::handleCompoundLiterals, transUnit );
     353                PASS( "Set Length From Initializer", Validate::setLengthFromInitializer, transUnit );
     354                PASS( "Find Global Decls", Validate::findGlobalDecls, transUnit );
     355                PASS( "Fix Label Address", Validate::fixLabelAddresses, transUnit );
    353356
    354357                if ( symtabp ) {
     
    361364                } // if
    362365
    363                 if ( validp ) {
    364                         dump( std::move( transUnit ) );
    365                         return EXIT_SUCCESS;
    366                 } // if
    367 
    368                 PASS( "Translate Throws", ControlStruct::translateThrows( transUnit ) );
    369                 PASS( "Fix Labels", ControlStruct::fixLabels( transUnit ) );
    370                 PASS( "Fix Names", CodeGen::fixNames( transUnit ) );
    371                 PASS( "Gen Init", InitTweak::genInit( transUnit ) );
    372                 PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( transUnit ) );
     366                DUMP( validp, std::move( transUnit ) );
     367
     368                PASS( "Translate Throws", ControlStruct::translateThrows, transUnit );
     369                PASS( "Fix Labels", ControlStruct::fixLabels, transUnit );
     370                PASS( "Fix Names", CodeGen::fixNames, transUnit );
     371                PASS( "Gen Init", InitTweak::genInit, transUnit );
     372                PASS( "Expand Member Tuples" , Tuples::expandMemberTuples, transUnit );
    373373
    374374                if ( libcfap ) {
     
    382382                } // if
    383383
    384                 if ( bresolvep ) {
    385                         dump( std::move( transUnit ) );
    386                         return EXIT_SUCCESS;
    387                 } // if
     384                DUMP( bresolvep, std::move( transUnit ) );
    388385
    389386                if ( resolvprotop ) {
     
    392389                } // if
    393390
    394                 PASS( "Resolve", ResolvExpr::resolve( transUnit ) );
    395                 if ( exprp ) {
    396                         dump( std::move( transUnit ) );
    397                         return EXIT_SUCCESS;
    398                 } // if
    399 
    400                 forceFillCodeLocations( transUnit );
    401 
    402                 PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary()));
     391                PASS( "Resolve", ResolvExpr::resolve, transUnit );
     392                DUMP( exprp, std::move( transUnit ) );
     393
     394                PASS( "Fix Init", InitTweak::fix, transUnit, buildingLibrary() );
    403395
    404396                // fix ObjectDecl - replaces ConstructorInit nodes
    405                 if ( ctorinitp ) {
    406                         dump( std::move( transUnit ) );
    407                         return EXIT_SUCCESS;
    408                 } // if
     397                DUMP( ctorinitp, std::move( transUnit ) );
    409398
    410399                // Currently not working due to unresolved issues with UniqueExpr
    411                 PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( transUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
    412 
    413                 PASS( "Translate Tries", ControlStruct::translateTries( transUnit ) );
    414                 PASS( "Gen Waitfor", Concurrency::generateWaitFor( transUnit ) );
     400                PASS( "Expand Unique Expr", Tuples::expandUniqueExpr, transUnit ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
     401
     402                PASS( "Translate Tries", ControlStruct::translateTries, transUnit );
     403                PASS( "Gen Waitfor", Concurrency::generateWaitFor, transUnit );
    415404
    416405                // Needs to happen before tuple types are expanded.
    417                 PASS( "Convert Specializations",  GenPoly::convertSpecializations( transUnit ) );
    418 
    419                 PASS( "Expand Tuples", Tuples::expandTuples( transUnit ) );
    420 
    421                 if ( tuplep ) {
    422                         dump( std::move( transUnit ) );
    423                         return EXIT_SUCCESS;
    424                 } // if
     406                PASS( "Convert Specializations",  GenPoly::convertSpecializations, transUnit );
     407
     408                PASS( "Expand Tuples", Tuples::expandTuples, transUnit );
     409                DUMP( tuplep, std::move( transUnit ) );
    425410
    426411                // Must come after Translate Tries.
    427                 PASS( "Virtual Expand Casts", Virtual::expandCasts( transUnit ) );
    428 
    429                 PASS( "Instantiate Generics", GenPoly::instantiateGeneric( transUnit ) );
    430                 if ( genericsp ) {
    431                         dump( std::move( transUnit ) );
    432                         return EXIT_SUCCESS;
    433                 } // if
    434 
    435                 PASS( "Convert L-Value", GenPoly::convertLvalue( transUnit ) );
     412                PASS( "Virtual Expand Casts", Virtual::expandCasts, transUnit );
     413
     414                PASS( "Instantiate Generics", GenPoly::instantiateGeneric, transUnit );
     415                DUMP( genericsp, std::move( transUnit ) );
     416
     417                PASS( "Convert L-Value", GenPoly::convertLvalue, transUnit );
    436418
    437419                translationUnit = convert( std::move( transUnit ) );
    438420
    439                 if ( bboxp ) {
    440                         dump( translationUnit );
    441                         return EXIT_SUCCESS;
    442                 } // if
    443                 PASS( "Box", GenPoly::box( translationUnit ) );
    444 
    445                 PASS( "Link-Once", CodeGen::translateLinkOnce( translationUnit ) );
     421                DUMP( bboxp, translationUnit );
     422                PASS( "Box", GenPoly::box, translationUnit );
     423
     424                PASS( "Link-Once", CodeGen::translateLinkOnce, translationUnit );
    446425
    447426                // Code has been lowered to C, now we can start generation.
    448427
    449                 if ( bcodegenp ) {
    450                         dump( translationUnit );
    451                         return EXIT_SUCCESS;
    452                 } // if
     428                DUMP( bcodegenp, translationUnit );
    453429
    454430                if ( optind < argc ) {                                                  // any commands after the flags and input file ? => output file name
     
    457433
    458434                CodeTools::fillLocations( translationUnit );
    459                 PASS( "Code Gen", CodeGen::generate( translationUnit, *output, ! genproto, prettycodegenp, true, linemarks ) );
     435                PASS( "Code Gen", CodeGen::generate, translationUnit, *output, ! genproto, prettycodegenp, true, linemarks );
    460436
    461437                CodeGen::FixMain::fix( translationUnit, *output,
     
    505481
    506482
    507 static const char optstring[] = ":c:ghlLmNnpdP:S:twW:D:";
     483static const char optstring[] = ":c:ghilLmNnpdP:S:twW:D:";
    508484
    509485enum { PreludeDir = 128 };
     
    512488        { "gdb", no_argument, nullptr, 'g' },
    513489        { "help", no_argument, nullptr, 'h' },
     490        { "invariant", no_argument, nullptr, 'i' },
    514491        { "libcfa", no_argument, nullptr, 'l' },
    515492        { "linemarks", no_argument, nullptr, 'L' },
    516         { "no-main", no_argument, 0, 'm' },
     493        { "no-main", no_argument, nullptr, 'm' },
    517494        { "no-linemarks", no_argument, nullptr, 'N' },
    518495        { "no-prelude", no_argument, nullptr, 'n' },
     
    533510        "wait for gdb to attach",                                                       // -g
    534511        "print translator help message",                                        // -h
     512        "invariant checking during AST passes",                         // -i
    535513        "generate libcfa.c",                                                            // -l
    536514        "generate line marks",                                                          // -L
     
    626604                        usage( argv );                                                          // no return
    627605                        break;
     606                  case 'i':                                                                             // invariant checking
     607                        invariant = true;
     608                        break;
    628609                  case 'l':                                                                             // generate libcfa.c
    629610                        libcfap = true;
Note: See TracChangeset for help on using the changeset viewer.