Changeset 14755e5 for src/ResolvExpr


Ignore:
Timestamp:
Feb 8, 2024, 11:07:42 AM (4 months ago)
Author:
Andrew Beach <ajbeach@…>
Branches:
master
Children:
3be6ef3
Parents:
956299b
Message:

Updated indentation in Resolver. Removed trailing whitespace.

Location:
src/ResolvExpr
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/CandidateFinder.cpp

    r956299b r14755e5  
    891891                } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) {
    892892                        addAggMembers( unionInst, aggrExpr, *cand, Cost::unsafe, "" );
    893                 }
    894                 else if ( auto enumInst = aggrExpr->result.as< ast::EnumInstType >() ) {
     893                } else if ( auto enumInst = aggrExpr->result.as< ast::EnumInstType >() ) {
    895894                        // The Attribute Arrays are not yet generated, need to proxy them
    896895                        // as attribute function call
     
    898897                        if ( enumInst->base && enumInst->base->base ) {
    899898                                auto valueName = new ast::NameExpr(location, "valueE");
    900                                 auto untypedValueCall = new ast::UntypedExpr( 
     899                                auto untypedValueCall = new ast::UntypedExpr(
    901900                                        location, valueName, { aggrExpr } );
    902901                                auto result = ResolvExpr::findVoidExpression( untypedValueCall, context );
     
    975974                                        }
    976975
    977                                         if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer);                                             
     976                                        if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer);
    978977                                        else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type));
    979978                                }
     
    12401239                                                restructureCast( cand->expr, toType, castExpr->isGenerated ),
    12411240                                                copy( cand->env ), std::move( open ), std::move( need ), cand->cost + thisCost);
    1242                                         // currently assertions are always resolved immediately so this should have no effect. 
     1241                                        // currently assertions are always resolved immediately so this should have no effect.
    12431242                                        // if this somehow changes in the future (e.g. delayed by indeterminate return type)
    12441243                                        // we may need to revisit the logic.
     
    14031402        void Finder::postvisit( const ast::VariableExpr * variableExpr ) {
    14041403                // not sufficient to just pass `variableExpr` here, type might have changed since
    1405                 addCandidate( variableExpr, tenv );             
     1404                addCandidate( variableExpr, tenv );
    14061405        }
    14071406
     
    17921791                                        CandidateRef newCand =
    17931792                                                std::make_shared<Candidate>(
    1794                                                         newExpr, copy( tenv ), ast::OpenVarSet{}, 
     1793                                                        newExpr, copy( tenv ), ast::OpenVarSet{},
    17951794                                                        ast::AssertionSet{}, Cost::zero, cost
    17961795                                                );
    1797                                        
     1796
    17981797                                        if (newCand->expr->env) {
    17991798                                                newCand->env.add(*newCand->expr->env);
  • src/ResolvExpr/Resolver.cc

    r956299b r14755e5  
    5050
    5151namespace ResolvExpr {
    52         namespace {
    53                 /// Finds deleted expressions in an expression tree
    54                 struct DeleteFinder final : public ast::WithShortCircuiting, public ast::WithVisitorRef<DeleteFinder> {
    55                         const ast::DeletedExpr * result = nullptr;
    56 
    57                         void previsit( const ast::DeletedExpr * expr ) {
    58                                 if ( result ) { visit_children = false; }
    59                                 else { result = expr; }
     52
     53namespace {
     54        /// Finds deleted expressions in an expression tree
     55        struct DeleteFinder final : public ast::WithShortCircuiting, public ast::WithVisitorRef<DeleteFinder> {
     56                const ast::DeletedExpr * result = nullptr;
     57
     58                void previsit( const ast::DeletedExpr * expr ) {
     59                        if ( result ) { visit_children = false; }
     60                        else { result = expr; }
     61                }
     62
     63                void previsit( const ast::Expr * expr ) {
     64                        if ( result ) { visit_children = false; }
     65                        if (expr->inferred.hasParams()) {
     66                                for (auto & imp : expr->inferred.inferParams() ) {
     67                                        imp.second.expr->accept(*visitor);
     68                                }
    6069                        }
    61 
    62                         void previsit( const ast::Expr * expr ) {
    63                                 if ( result ) { visit_children = false; }
    64                                 if (expr->inferred.hasParams()) {
    65                                         for (auto & imp : expr->inferred.inferParams() ) {
    66                                                 imp.second.expr->accept(*visitor);
     70                }
     71        };
     72
     73        struct ResolveDesignators final : public ast::WithShortCircuiting {
     74                ResolveContext& context;
     75                bool result = false;
     76
     77                ResolveDesignators( ResolveContext& _context ): context(_context) {};
     78
     79                void previsit( const ast::Node * ) {
     80                        // short circuit if we already know there are designations
     81                        if ( result ) visit_children = false;
     82                }
     83
     84                void previsit( const ast::Designation * des ) {
     85                        if ( result ) visit_children = false;
     86                        else if ( ! des->designators.empty() ) {
     87                                if ( (des->designators.size() == 1) ) {
     88                                        const ast::Expr * designator = des->designators.at(0);
     89                                        if ( const ast::NameExpr * designatorName = dynamic_cast<const ast::NameExpr *>(designator) ) {
     90                                                auto candidates = context.symtab.lookupId(designatorName->name);
     91                                                for ( auto candidate : candidates ) {
     92                                                        if ( dynamic_cast<const ast::EnumInstType *>(candidate.id->get_type()) ) {
     93                                                                result = true;
     94                                                                break;
     95                                                        }
     96                                                }
     97                                        }
     98                                }
     99                                visit_children = false;
     100                        }
     101                }
     102        };
     103} // anonymous namespace
     104
     105/// Check if this expression is or includes a deleted expression
     106const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) {
     107        return ast::Pass<DeleteFinder>::read( expr );
     108}
     109
     110namespace {
     111        /// always-accept candidate filter
     112        bool anyCandidate( const Candidate & ) { return true; }
     113
     114        /// Calls the CandidateFinder and finds the single best candidate
     115        CandidateRef findUnfinishedKindExpression(
     116                const ast::Expr * untyped, const ResolveContext & context, const std::string & kind,
     117                std::function<bool(const Candidate &)> pred = anyCandidate, ResolveMode mode = {}
     118        ) {
     119                if ( ! untyped ) return nullptr;
     120
     121                // xxx - this isn't thread-safe, but should work until we parallelize the resolver
     122                static unsigned recursion_level = 0;
     123
     124                ++recursion_level;
     125                ast::TypeEnvironment env;
     126                CandidateFinder finder( context, env );
     127                finder.allowVoid = true;
     128                finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );
     129                --recursion_level;
     130
     131                // produce a filtered list of candidates
     132                CandidateList candidates;
     133                for ( auto & cand : finder.candidates ) {
     134                        if ( pred( *cand ) ) { candidates.emplace_back( cand ); }
     135                }
     136
     137                // produce invalid error if no candidates
     138                if ( candidates.empty() ) {
     139                        SemanticError( untyped,
     140                                toString( "No reasonable alternatives for ", kind, (kind != "" ? " " : ""),
     141                                "expression: ") );
     142                }
     143
     144                // search for cheapest candidate
     145                CandidateList winners;
     146                bool seen_undeleted = false;
     147                for ( CandidateRef & cand : candidates ) {
     148                        int c = winners.empty() ? -1 : cand->cost.compare( winners.front()->cost );
     149
     150                        if ( c > 0 ) continue;  // skip more expensive than winner
     151
     152                        if ( c < 0 ) {
     153                                // reset on new cheapest
     154                                seen_undeleted = ! findDeletedExpr( cand->expr );
     155                                winners.clear();
     156                        } else /* if ( c == 0 ) */ {
     157                                if ( findDeletedExpr( cand->expr ) ) {
     158                                        // skip deleted expression if already seen one equivalent-cost not
     159                                        if ( seen_undeleted ) continue;
     160                                } else if ( ! seen_undeleted ) {
     161                                        // replace list of equivalent-cost deleted expressions with one non-deleted
     162                                        winners.clear();
     163                                        seen_undeleted = true;
     164                                }
     165                        }
     166
     167                        winners.emplace_back( std::move( cand ) );
     168                }
     169
     170                // promote candidate.cvtCost to .cost
     171                // promoteCvtCost( winners );
     172
     173                // produce ambiguous errors, if applicable
     174                if ( winners.size() != 1 ) {
     175                        std::ostringstream stream;
     176                        stream << "Cannot choose between " << winners.size() << " alternatives for "
     177                                << kind << (kind != "" ? " " : "") << "expression\n";
     178                        ast::print( stream, untyped );
     179                        stream << " Alternatives are:\n";
     180                        print( stream, winners, 1 );
     181                        SemanticError( untyped->location, stream.str() );
     182                }
     183
     184                // single selected choice
     185                CandidateRef & choice = winners.front();
     186
     187                // fail on only expression deleted
     188                if ( ! seen_undeleted ) {
     189                        SemanticError( untyped->location, choice->expr.get(), "Unique best alternative "
     190                        "includes deleted identifier in " );
     191                }
     192
     193                return std::move( choice );
     194        }
     195
     196        /// Strips extraneous casts out of an expression
     197        struct StripCasts final {
     198                const ast::Expr * postvisit( const ast::CastExpr * castExpr ) {
     199                        if (
     200                                castExpr->isGenerated == ast::GeneratedCast
     201                                && typesCompatible( castExpr->arg->result, castExpr->result )
     202                        ) {
     203                                // generated cast is the same type as its argument, remove it after keeping env
     204                                return ast::mutate_field(
     205                                        castExpr->arg.get(), &ast::Expr::env, castExpr->env );
     206                        }
     207                        return castExpr;
     208                }
     209
     210                static void strip( ast::ptr< ast::Expr > & expr ) {
     211                        ast::Pass< StripCasts > stripper;
     212                        expr = expr->accept( stripper );
     213                }
     214        };
     215
     216        /// Swaps argument into expression pointer, saving original environment
     217        void swap_and_save_env( ast::ptr< ast::Expr > & expr, const ast::Expr * newExpr ) {
     218                ast::ptr< ast::TypeSubstitution > env = expr->env;
     219                expr.set_and_mutate( newExpr )->env = env;
     220        }
     221
     222        /// Removes cast to type of argument (unlike StripCasts, also handles non-generated casts)
     223        void removeExtraneousCast( ast::ptr<ast::Expr> & expr ) {
     224                if ( const ast::CastExpr * castExpr = expr.as< ast::CastExpr >() ) {
     225                        if ( typesCompatible( castExpr->arg->result, castExpr->result ) ) {
     226                                // cast is to the same type as its argument, remove it
     227                                swap_and_save_env( expr, castExpr->arg );
     228                        }
     229                }
     230        }
     231
     232} // anonymous namespace
     233
     234/// Establish post-resolver invariants for expressions
     235void finishExpr(
     236        ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env,
     237        const ast::TypeSubstitution * oldenv = nullptr
     238) {
     239        // set up new type substitution for expression
     240        ast::ptr< ast::TypeSubstitution > newenv =
     241                 oldenv ? oldenv : new ast::TypeSubstitution{};
     242        env.writeToSubstitution( *newenv.get_and_mutate() );
     243        expr.get_and_mutate()->env = std::move( newenv );
     244        // remove unncecessary casts
     245        StripCasts::strip( expr );
     246}
     247
     248ast::ptr< ast::Expr > resolveInVoidContext(
     249        const ast::Expr * expr, const ResolveContext & context,
     250        ast::TypeEnvironment & env
     251) {
     252        assertf( expr, "expected a non-null expression" );
     253
     254        // set up and resolve expression cast to void
     255        ast::ptr< ast::CastExpr > untyped = new ast::CastExpr{ expr };
     256        CandidateRef choice = findUnfinishedKindExpression(
     257                untyped, context, "", anyCandidate, ResolveMode::withAdjustment() );
     258
     259        // a cast expression has either 0 or 1 interpretations (by language rules);
     260        // if 0, an exception has already been thrown, and this code will not run
     261        const ast::CastExpr * castExpr = choice->expr.strict_as< ast::CastExpr >();
     262        env = std::move( choice->env );
     263
     264        return castExpr->arg;
     265}
     266
     267/// Resolve `untyped` to the expression whose candidate is the best match for a `void`
     268/// context.
     269ast::ptr< ast::Expr > findVoidExpression(
     270        const ast::Expr * untyped, const ResolveContext & context
     271) {
     272        ast::TypeEnvironment env;
     273        ast::ptr< ast::Expr > newExpr = resolveInVoidContext( untyped, context, env );
     274        finishExpr( newExpr, env, untyped->env );
     275        return newExpr;
     276}
     277
     278namespace {
     279        /// resolve `untyped` to the expression whose candidate satisfies `pred` with the
     280        /// lowest cost, returning the resolved version
     281        ast::ptr< ast::Expr > findKindExpression(
     282                const ast::Expr * untyped, const ResolveContext & context,
     283                std::function<bool(const Candidate &)> pred = anyCandidate,
     284                const std::string & kind = "", ResolveMode mode = {}
     285        ) {
     286                if ( ! untyped ) return {};
     287                CandidateRef choice =
     288                        findUnfinishedKindExpression( untyped, context, kind, pred, mode );
     289                ResolvExpr::finishExpr( choice->expr, choice->env, untyped->env );
     290                return std::move( choice->expr );
     291        }
     292
     293        /// Resolve `untyped` to the single expression whose candidate is the best match
     294        ast::ptr< ast::Expr > findSingleExpression(
     295                const ast::Expr * untyped, const ResolveContext & context
     296        ) {
     297                Stats::ResolveTime::start( untyped );
     298                auto res = findKindExpression( untyped, context );
     299                Stats::ResolveTime::stop();
     300                return res;
     301        }
     302} // anonymous namespace
     303
     304ast::ptr< ast::Expr > findSingleExpression(
     305        const ast::Expr * untyped, const ast::Type * type,
     306        const ResolveContext & context
     307) {
     308        assert( untyped && type );
     309        ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type };
     310        ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, context );
     311        removeExtraneousCast( newExpr );
     312        return newExpr;
     313}
     314
     315namespace {
     316        bool structOrUnion( const Candidate & i ) {
     317                const ast::Type * t = i.expr->result->stripReferences();
     318                return dynamic_cast< const ast::StructInstType * >( t ) || dynamic_cast< const ast::UnionInstType * >( t );
     319        }
     320        /// Predicate for "Candidate has integral type"
     321        bool hasIntegralType( const Candidate & i ) {
     322                const ast::Type * type = i.expr->result;
     323
     324                if ( auto bt = dynamic_cast< const ast::BasicType * >( type ) ) {
     325                        return bt->isInteger();
     326                } else if (
     327                        dynamic_cast< const ast::EnumInstType * >( type )
     328                        || dynamic_cast< const ast::ZeroType * >( type )
     329                        || dynamic_cast< const ast::OneType * >( type )
     330                ) {
     331                        return true;
     332                } else return false;
     333        }
     334
     335        /// Resolve `untyped` as an integral expression, returning the resolved version
     336        ast::ptr< ast::Expr > findIntegralExpression(
     337                const ast::Expr * untyped, const ResolveContext & context
     338        ) {
     339                return findKindExpression( untyped, context, hasIntegralType, "condition" );
     340        }
     341
     342        /// check if a type is a character type
     343        bool isCharType( const ast::Type * t ) {
     344                if ( auto bt = dynamic_cast< const ast::BasicType * >( t ) ) {
     345                        return bt->kind == ast::BasicType::Char
     346                                || bt->kind == ast::BasicType::SignedChar
     347                                || bt->kind == ast::BasicType::UnsignedChar;
     348                }
     349                return false;
     350        }
     351
     352        /// Advance a type itertor to the next mutex parameter
     353        template<typename Iter>
     354        inline bool nextMutex( Iter & it, const Iter & end ) {
     355                while ( it != end && ! (*it)->is_mutex() ) { ++it; }
     356                return it != end;
     357        }
     358}
     359
     360class Resolver final
     361: public ast::WithSymbolTable, public ast::WithGuards,
     362  public ast::WithVisitorRef<Resolver>, public ast::WithShortCircuiting,
     363  public ast::WithStmtsToAdd<> {
     364
     365        ast::ptr< ast::Type > functionReturn = nullptr;
     366        ast::CurrentObject currentObject;
     367        // for work previously in GenInit
     368        static InitTweak::ManagedTypes managedTypes;
     369        ResolveContext context;
     370
     371        bool inEnumDecl = false;
     372
     373public:
     374        static size_t traceId;
     375        Resolver( const ast::TranslationGlobal & global ) :
     376                ast::WithSymbolTable(ast::SymbolTable::ErrorDetection::ValidateOnAdd),
     377                context{ symtab, global } {}
     378        Resolver( const ResolveContext & context ) :
     379                ast::WithSymbolTable{ context.symtab },
     380                context{ symtab, context.global } {}
     381
     382        const ast::FunctionDecl * previsit( const ast::FunctionDecl * );
     383        const ast::FunctionDecl * postvisit( const ast::FunctionDecl * );
     384        const ast::ObjectDecl * previsit( const ast::ObjectDecl * );
     385        void previsit( const ast::AggregateDecl * );
     386        void previsit( const ast::StructDecl * );
     387        void previsit( const ast::EnumDecl * );
     388        const ast::StaticAssertDecl * previsit( const ast::StaticAssertDecl * );
     389
     390        const ast::ArrayType * previsit( const ast::ArrayType * );
     391        const ast::PointerType * previsit( const ast::PointerType * );
     392
     393        const ast::ExprStmt *        previsit( const ast::ExprStmt * );
     394        const ast::AsmExpr *         previsit( const ast::AsmExpr * );
     395        const ast::AsmStmt *         previsit( const ast::AsmStmt * );
     396        const ast::IfStmt *          previsit( const ast::IfStmt * );
     397        const ast::WhileDoStmt *     previsit( const ast::WhileDoStmt * );
     398        const ast::ForStmt *         previsit( const ast::ForStmt * );
     399        const ast::SwitchStmt *      previsit( const ast::SwitchStmt * );
     400        const ast::CaseClause *      previsit( const ast::CaseClause * );
     401        const ast::BranchStmt *      previsit( const ast::BranchStmt * );
     402        const ast::ReturnStmt *      previsit( const ast::ReturnStmt * );
     403        const ast::ThrowStmt *       previsit( const ast::ThrowStmt * );
     404        const ast::CatchClause *     previsit( const ast::CatchClause * );
     405        const ast::CatchClause *     postvisit( const ast::CatchClause * );
     406        const ast::WaitForStmt *     previsit( const ast::WaitForStmt * );
     407        const ast::WithStmt *        previsit( const ast::WithStmt * );
     408
     409        const ast::SingleInit *      previsit( const ast::SingleInit * );
     410        const ast::ListInit *        previsit( const ast::ListInit * );
     411        const ast::ConstructorInit * previsit( const ast::ConstructorInit * );
     412
     413        void resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd);
     414
     415        void beginScope() { managedTypes.beginScope(); }
     416        void endScope() { managedTypes.endScope(); }
     417        bool on_error(ast::ptr<ast::Decl> & decl);
     418};
     419// size_t Resolver::traceId = Stats::Heap::new_stacktrace_id("Resolver");
     420
     421InitTweak::ManagedTypes Resolver::managedTypes;
     422
     423void resolve( ast::TranslationUnit& translationUnit ) {
     424        ast::Pass< Resolver >::run( translationUnit, translationUnit.global );
     425}
     426
     427ast::ptr< ast::Init > resolveCtorInit(
     428        const ast::ConstructorInit * ctorInit, const ResolveContext & context
     429) {
     430        assert( ctorInit );
     431        ast::Pass< Resolver > resolver( context );
     432        return ctorInit->accept( resolver );
     433}
     434
     435const ast::Expr * resolveStmtExpr(
     436        const ast::StmtExpr * stmtExpr, const ResolveContext & context
     437) {
     438        assert( stmtExpr );
     439        ast::Pass< Resolver > resolver( context );
     440        auto ret = mutate(stmtExpr->accept(resolver));
     441        strict_dynamic_cast< ast::StmtExpr * >( ret )->computeResult();
     442        return ret;
     443}
     444
     445namespace {
     446        const ast::Attribute * handleAttribute(const CodeLocation & loc, const ast::Attribute * attr, const ResolveContext & context) {
     447                std::string name = attr->normalizedName();
     448                if (name == "constructor" || name == "destructor") {
     449                        if (attr->params.size() == 1) {
     450                                auto arg = attr->params.front();
     451                                auto resolved = ResolvExpr::findSingleExpression( arg, new ast::BasicType( ast::BasicType::LongLongSignedInt ), context );
     452                                auto result = eval(arg);
     453
     454                                auto mutAttr = mutate(attr);
     455                                mutAttr->params.front() = resolved;
     456                                if (! result.hasKnownValue) {
     457                                        SemanticWarning(loc, Warning::GccAttributes,
     458                                                toCString( name, " priorities must be integers from 0 to 65535 inclusive: ", arg ) );
     459                                }
     460                                else {
     461                                        auto priority = result.knownValue;
     462                                        if (priority < 101) {
     463                                                SemanticWarning(loc, Warning::GccAttributes,
     464                                                        toCString( name, " priorities from 0 to 100 are reserved for the implementation" ) );
     465                                        } else if (priority < 201 && ! buildingLibrary()) {
     466                                                SemanticWarning(loc, Warning::GccAttributes,
     467                                                        toCString( name, " priorities from 101 to 200 are reserved for the implementation" ) );
     468                                        }
     469                                }
     470                                return mutAttr;
     471                        } else if (attr->params.size() > 1) {
     472                                SemanticWarning(loc, Warning::GccAttributes, toCString( "too many arguments to ", name, " attribute" ) );
     473                        } else {
     474                                SemanticWarning(loc, Warning::GccAttributes, toCString( "too few arguments to ", name, " attribute" ) );
     475                        }
     476                }
     477                return attr;
     478        }
     479}
     480
     481const ast::FunctionDecl * Resolver::previsit( const ast::FunctionDecl * functionDecl ) {
     482        GuardValue( functionReturn );
     483
     484        assert (functionDecl->unique());
     485        if (!functionDecl->has_body() && !functionDecl->withExprs.empty()) {
     486                SemanticError(functionDecl->location, functionDecl, "Function without body has with declarations");
     487        }
     488
     489        if (!functionDecl->isTypeFixed) {
     490                auto mutDecl = mutate(functionDecl);
     491                auto mutType = mutDecl->type.get_and_mutate();
     492
     493                for (auto & attr: mutDecl->attributes) {
     494                        attr = handleAttribute(mutDecl->location, attr, context );
     495                }
     496
     497                // handle assertions
     498
     499                symtab.enterScope();
     500                mutType->forall.clear();
     501                mutType->assertions.clear();
     502                for (auto & typeParam : mutDecl->type_params) {
     503                        symtab.addType(typeParam);
     504                        mutType->forall.emplace_back(new ast::TypeInstType(typeParam));
     505                }
     506                for (auto & asst : mutDecl->assertions) {
     507                        asst = fixObjectType(asst.strict_as<ast::ObjectDecl>(), context);
     508                        symtab.addId(asst);
     509                        mutType->assertions.emplace_back(new ast::VariableExpr(functionDecl->location, asst));
     510                }
     511
     512                // temporarily adds params to symbol table.
     513                // actual scoping rules for params and withexprs differ - see Pass::visit(FunctionDecl)
     514
     515                std::vector<ast::ptr<ast::Type>> paramTypes;
     516                std::vector<ast::ptr<ast::Type>> returnTypes;
     517
     518                for (auto & param : mutDecl->params) {
     519                        param = fixObjectType(param.strict_as<ast::ObjectDecl>(), context);
     520                        symtab.addId(param);
     521                        paramTypes.emplace_back(param->get_type());
     522                }
     523                for (auto & ret : mutDecl->returns) {
     524                        ret = fixObjectType(ret.strict_as<ast::ObjectDecl>(), context);
     525                        returnTypes.emplace_back(ret->get_type());
     526                }
     527                // since function type in decl is just a view of param types, need to update that as well
     528                mutType->params = std::move(paramTypes);
     529                mutType->returns = std::move(returnTypes);
     530
     531                auto renamedType = strict_dynamic_cast<const ast::FunctionType *>(renameTyVars(mutType, RenameMode::GEN_EXPR_ID));
     532
     533                std::list<ast::ptr<ast::Stmt>> newStmts;
     534                resolveWithExprs (mutDecl->withExprs, newStmts);
     535
     536                if (mutDecl->stmts) {
     537                        auto mutStmt = mutDecl->stmts.get_and_mutate();
     538                        mutStmt->kids.splice(mutStmt->kids.begin(), std::move(newStmts));
     539                        mutDecl->stmts = mutStmt;
     540                }
     541
     542                symtab.leaveScope();
     543
     544                mutDecl->type = renamedType;
     545                mutDecl->mangleName = Mangle::mangle(mutDecl);
     546                mutDecl->isTypeFixed = true;
     547                functionDecl = mutDecl;
     548        }
     549        managedTypes.handleDWT(functionDecl);
     550
     551        functionReturn = extractResultType( functionDecl->type );
     552        return functionDecl;
     553}
     554
     555const ast::FunctionDecl * Resolver::postvisit( const ast::FunctionDecl * functionDecl ) {
     556        // default value expressions have an environment which shouldn't be there and trips up
     557        // later passes.
     558        assert( functionDecl->unique() );
     559        ast::FunctionType * mutType = mutate( functionDecl->type.get() );
     560
     561        for ( unsigned i = 0 ; i < mutType->params.size() ; ++i ) {
     562                if ( const ast::ObjectDecl * obj = mutType->params[i].as< ast::ObjectDecl >() ) {
     563                        if ( const ast::SingleInit * init = obj->init.as< ast::SingleInit >() ) {
     564                                if ( init->value->env == nullptr ) continue;
     565                                // clone initializer minus the initializer environment
     566                                auto mutParam = mutate( mutType->params[i].strict_as< ast::ObjectDecl >() );
     567                                auto mutInit = mutate( mutParam->init.strict_as< ast::SingleInit >() );
     568                                auto mutValue = mutate( mutInit->value.get() );
     569
     570                                mutValue->env = nullptr;
     571                                mutInit->value = mutValue;
     572                                mutParam->init = mutInit;
     573                                mutType->params[i] = mutParam;
     574
     575                                assert( ! mutType->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env);
     576                        }
     577                }
     578        }
     579        mutate_field(functionDecl, &ast::FunctionDecl::type, mutType);
     580        return functionDecl;
     581}
     582
     583const ast::ObjectDecl * Resolver::previsit( const ast::ObjectDecl * objectDecl ) {
     584        // To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()],
     585        // class-variable `initContext` is changed multiple times because the LHS is analyzed
     586        // twice. The second analysis changes `initContext` because a function type can contain
     587        // object declarations in the return and parameter types. Therefore each value of
     588        // `initContext` is retained so the type on the first analysis is preserved and used for
     589        // selecting the RHS.
     590        GuardValue( currentObject );
     591
     592        if ( inEnumDecl && dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() ) ) {
     593                // enumerator initializers should not use the enum type to initialize, since the
     594                // enum type is still incomplete at this point. Use `int` instead.
     595
     596                if ( auto enumBase = dynamic_cast< const ast::EnumInstType * >
     597                        ( objectDecl->get_type() )->base->base ) {
     598                        objectDecl = fixObjectType( objectDecl, context );
     599                        currentObject = ast::CurrentObject{
     600                                objectDecl->location,
     601                                enumBase
     602                        };
     603                } else {
     604                        objectDecl = fixObjectType( objectDecl, context );
     605                        currentObject = ast::CurrentObject{
     606                                objectDecl->location, new ast::BasicType{ ast::BasicType::SignedInt } };
     607                }
     608        } else {
     609                if ( !objectDecl->isTypeFixed ) {
     610                        auto newDecl = fixObjectType(objectDecl, context);
     611                        auto mutDecl = mutate(newDecl);
     612
     613                        // generate CtorInit wrapper when necessary.
     614                        // in certain cases, fixObjectType is called before reaching
     615                        // this object in visitor pass, thus disabling CtorInit codegen.
     616                        // this happens on aggregate members and function parameters.
     617                        if ( InitTweak::tryConstruct( mutDecl ) && ( managedTypes.isManaged( mutDecl ) || ((! isInFunction() || mutDecl->storage.is_static ) && ! InitTweak::isConstExpr( mutDecl->init ) ) ) ) {
     618                                // constructed objects cannot be designated
     619                                if ( InitTweak::isDesignated( mutDecl->init ) ) {
     620                                        ast::Pass<ResolveDesignators> res( context );
     621                                        maybe_accept( mutDecl->init.get(), res );
     622                                        if ( !res.core.result ) {
     623                                                SemanticError( mutDecl, "Cannot include designations in the initializer for a managed Object.\n"
     624                                                                           "If this is really what you want, initialize with @=." );
     625                                        }
     626                                }
     627                                // constructed objects should not have initializers nested too deeply
     628                                if ( ! InitTweak::checkInitDepth( mutDecl ) ) SemanticError( mutDecl, "Managed object's initializer is too deep " );
     629
     630                                mutDecl->init = InitTweak::genCtorInit( mutDecl->location, mutDecl );
     631                        }
     632
     633                        objectDecl = mutDecl;
     634                }
     635                currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() };
     636        }
     637
     638        return objectDecl;
     639}
     640
     641void Resolver::previsit( const ast::AggregateDecl * _aggDecl ) {
     642        auto aggDecl = mutate(_aggDecl);
     643        assertf(aggDecl == _aggDecl, "type declarations must be unique");
     644
     645        for (auto & member: aggDecl->members) {
     646                // nested type decls are hoisted already. no need to do anything
     647                if (auto obj = member.as<ast::ObjectDecl>()) {
     648                        member = fixObjectType(obj, context);
     649                }
     650        }
     651}
     652
     653void Resolver::previsit( const ast::StructDecl * structDecl ) {
     654        previsit(static_cast<const ast::AggregateDecl *>(structDecl));
     655        managedTypes.handleStruct(structDecl);
     656}
     657
     658void Resolver::previsit( const ast::EnumDecl * ) {
     659        // in case we decide to allow nested enums
     660        GuardValue( inEnumDecl );
     661        inEnumDecl = true;
     662        // don't need to fix types for enum fields
     663}
     664
     665const ast::StaticAssertDecl * Resolver::previsit(
     666        const ast::StaticAssertDecl * assertDecl
     667) {
     668        return ast::mutate_field(
     669                assertDecl, &ast::StaticAssertDecl::cond,
     670                findIntegralExpression( assertDecl->cond, context ) );
     671}
     672
     673template< typename PtrType >
     674const PtrType * handlePtrType( const PtrType * type, const ResolveContext & context ) {
     675        if ( type->dimension ) {
     676                const ast::Type * sizeType = context.global.sizeType.get();
     677                ast::ptr< ast::Expr > dimension = findSingleExpression( type->dimension, sizeType, context );
     678                assertf(dimension->env->empty(), "array dimension expr has nonempty env");
     679                dimension.get_and_mutate()->env = nullptr;
     680                ast::mutate_field( type, &PtrType::dimension, dimension );
     681        }
     682        return type;
     683}
     684
     685const ast::ArrayType * Resolver::previsit( const ast::ArrayType * at ) {
     686        return handlePtrType( at, context );
     687}
     688
     689const ast::PointerType * Resolver::previsit( const ast::PointerType * pt ) {
     690        return handlePtrType( pt, context );
     691}
     692
     693const ast::ExprStmt * Resolver::previsit( const ast::ExprStmt * exprStmt ) {
     694        visit_children = false;
     695        assertf( exprStmt->expr, "ExprStmt has null expression in resolver" );
     696
     697        return ast::mutate_field(
     698                exprStmt, &ast::ExprStmt::expr, findVoidExpression( exprStmt->expr, context ) );
     699}
     700
     701const ast::AsmExpr * Resolver::previsit( const ast::AsmExpr * asmExpr ) {
     702        visit_children = false;
     703
     704        asmExpr = ast::mutate_field(
     705                asmExpr, &ast::AsmExpr::operand, findVoidExpression( asmExpr->operand, context ) );
     706
     707        return asmExpr;
     708}
     709
     710const ast::AsmStmt * Resolver::previsit( const ast::AsmStmt * asmStmt ) {
     711        visitor->maybe_accept( asmStmt, &ast::AsmStmt::input );
     712        visitor->maybe_accept( asmStmt, &ast::AsmStmt::output );
     713        visit_children = false;
     714        return asmStmt;
     715}
     716
     717const ast::IfStmt * Resolver::previsit( const ast::IfStmt * ifStmt ) {
     718        return ast::mutate_field(
     719                ifStmt, &ast::IfStmt::cond, findIntegralExpression( ifStmt->cond, context ) );
     720}
     721
     722const ast::WhileDoStmt * Resolver::previsit( const ast::WhileDoStmt * whileDoStmt ) {
     723        return ast::mutate_field(
     724                whileDoStmt, &ast::WhileDoStmt::cond, findIntegralExpression( whileDoStmt->cond, context ) );
     725}
     726
     727const ast::ForStmt * Resolver::previsit( const ast::ForStmt * forStmt ) {
     728        if ( forStmt->cond ) {
     729                forStmt = ast::mutate_field(
     730                        forStmt, &ast::ForStmt::cond, findIntegralExpression( forStmt->cond, context ) );
     731        }
     732
     733        if ( forStmt->inc ) {
     734                forStmt = ast::mutate_field(
     735                        forStmt, &ast::ForStmt::inc, findVoidExpression( forStmt->inc, context ) );
     736        }
     737
     738        return forStmt;
     739}
     740
     741const ast::SwitchStmt * Resolver::previsit( const ast::SwitchStmt * switchStmt ) {
     742        GuardValue( currentObject );
     743        switchStmt = ast::mutate_field(
     744                switchStmt, &ast::SwitchStmt::cond,
     745                findIntegralExpression( switchStmt->cond, context ) );
     746        currentObject = ast::CurrentObject{ switchStmt->location, switchStmt->cond->result };
     747        return switchStmt;
     748}
     749
     750const ast::CaseClause * Resolver::previsit( const ast::CaseClause * caseStmt ) {
     751        if ( caseStmt->cond ) {
     752                std::deque< ast::InitAlternative > initAlts = currentObject.getOptions();
     753                assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral "
     754                        "expression." );
     755
     756                ast::ptr< ast::Expr > untyped =
     757                        new ast::CastExpr{ caseStmt->location, caseStmt->cond, initAlts.front().type };
     758                ast::ptr< ast::Expr > newExpr = findSingleExpression( untyped, context );
     759
     760                // case condition cannot have a cast in C, so it must be removed here, regardless of
     761                // whether it would perform a conversion.
     762                if ( const ast::CastExpr * castExpr = newExpr.as< ast::CastExpr >() ) {
     763                        swap_and_save_env( newExpr, castExpr->arg );
     764                }
     765
     766                caseStmt = ast::mutate_field( caseStmt, &ast::CaseClause::cond, newExpr );
     767        }
     768        return caseStmt;
     769}
     770
     771const ast::BranchStmt * Resolver::previsit( const ast::BranchStmt * branchStmt ) {
     772        visit_children = false;
     773        // must resolve the argument of a computed goto
     774        if ( branchStmt->kind == ast::BranchStmt::Goto && branchStmt->computedTarget ) {
     775                // computed goto argument is void*
     776                ast::ptr< ast::Type > target = new ast::PointerType{ new ast::VoidType{} };
     777                branchStmt = ast::mutate_field(
     778                        branchStmt, &ast::BranchStmt::computedTarget,
     779                        findSingleExpression( branchStmt->computedTarget, target, context ) );
     780        }
     781        return branchStmt;
     782}
     783
     784const ast::ReturnStmt * Resolver::previsit( const ast::ReturnStmt * returnStmt ) {
     785        visit_children = false;
     786        if ( returnStmt->expr ) {
     787                returnStmt = ast::mutate_field(
     788                        returnStmt, &ast::ReturnStmt::expr,
     789                        findSingleExpression( returnStmt->expr, functionReturn, context ) );
     790        }
     791        return returnStmt;
     792}
     793
     794const ast::ThrowStmt * Resolver::previsit( const ast::ThrowStmt * throwStmt ) {
     795        visit_children = false;
     796        if ( throwStmt->expr ) {
     797                const ast::StructDecl * exceptionDecl =
     798                        symtab.lookupStruct( "__cfaehm_base_exception_t" );
     799                assert( exceptionDecl );
     800                ast::ptr< ast::Type > exceptType =
     801                        new ast::PointerType{ new ast::StructInstType{ exceptionDecl } };
     802                throwStmt = ast::mutate_field(
     803                        throwStmt, &ast::ThrowStmt::expr,
     804                        findSingleExpression( throwStmt->expr, exceptType, context ) );
     805        }
     806        return throwStmt;
     807}
     808
     809const ast::CatchClause * Resolver::previsit( const ast::CatchClause * catchClause ) {
     810        // Until we are very sure this invarent (ifs that move between passes have then)
     811        // holds, check it. This allows a check for when to decode the mangling.
     812        if ( auto ifStmt = catchClause->body.as<ast::IfStmt>() ) {
     813                assert( ifStmt->then );
     814        }
     815        // Encode the catchStmt so the condition can see the declaration.
     816        if ( catchClause->cond ) {
     817                ast::CatchClause * clause = mutate( catchClause );
     818                clause->body = new ast::IfStmt( clause->location, clause->cond, nullptr, clause->body );
     819                clause->cond = nullptr;
     820                return clause;
     821        }
     822        return catchClause;
     823}
     824
     825const ast::CatchClause * Resolver::postvisit( const ast::CatchClause * catchClause ) {
     826        // Decode the catchStmt so everything is stored properly.
     827        const ast::IfStmt * ifStmt = catchClause->body.as<ast::IfStmt>();
     828        if ( nullptr != ifStmt && nullptr == ifStmt->then ) {
     829                assert( ifStmt->cond );
     830                assert( ifStmt->else_ );
     831                ast::CatchClause * clause = ast::mutate( catchClause );
     832                clause->cond = ifStmt->cond;
     833                clause->body = ifStmt->else_;
     834                // ifStmt should be implicately deleted here.
     835                return clause;
     836        }
     837        return catchClause;
     838}
     839
     840const ast::WaitForStmt * Resolver::previsit( const ast::WaitForStmt * stmt ) {
     841        visit_children = false;
     842
     843        // Resolve all clauses first
     844        for ( unsigned i = 0; i < stmt->clauses.size(); ++i ) {
     845                const ast::WaitForClause & clause = *stmt->clauses[i];
     846
     847                ast::TypeEnvironment env;
     848                CandidateFinder funcFinder( context, env );
     849
     850                // Find all candidates for a function in canonical form
     851                funcFinder.find( clause.target, ResolveMode::withAdjustment() );
     852
     853                if ( funcFinder.candidates.empty() ) {
     854                        stringstream ss;
     855                        ss << "Use of undeclared indentifier '";
     856                        ss << clause.target.strict_as< ast::NameExpr >()->name;
     857                        ss << "' in call to waitfor";
     858                        SemanticError( stmt->location, ss.str() );
     859                }
     860
     861                if ( clause.target_args.empty() ) {
     862                        SemanticError( stmt->location,
     863                                "Waitfor clause must have at least one mutex parameter");
     864                }
     865
     866                // Find all alternatives for all arguments in canonical form
     867                std::vector< CandidateFinder > argFinders =
     868                        funcFinder.findSubExprs( clause.target_args );
     869
     870                // List all combinations of arguments
     871                std::vector< CandidateList > possibilities;
     872                combos( argFinders.begin(), argFinders.end(), back_inserter( possibilities ) );
     873
     874                // For every possible function:
     875                // * try matching the arguments to the parameters, not the other way around because
     876                //   more arguments than parameters
     877                CandidateList funcCandidates;
     878                std::vector< CandidateList > argsCandidates;
     879                SemanticErrorException errors;
     880                for ( CandidateRef & func : funcFinder.candidates ) {
     881                        try {
     882                                auto pointerType = dynamic_cast< const ast::PointerType * >(
     883                                        func->expr->result->stripReferences() );
     884                                if ( ! pointerType ) {
     885                                        SemanticError( stmt->location, func->expr->result.get(),
     886                                                "candidate not viable: not a pointer type\n" );
     887                                }
     888
     889                                auto funcType = pointerType->base.as< ast::FunctionType >();
     890                                if ( ! funcType ) {
     891                                        SemanticError( stmt->location, func->expr->result.get(),
     892                                                "candidate not viable: not a function type\n" );
     893                                }
     894
     895                                {
     896                                        auto param    = funcType->params.begin();
     897                                        auto paramEnd = funcType->params.end();
     898
     899                                        if( ! nextMutex( param, paramEnd ) ) {
     900                                                SemanticError( stmt->location, funcType,
     901                                                        "candidate function not viable: no mutex parameters\n");
     902                                        }
     903                                }
     904
     905                                CandidateRef func2{ new Candidate{ *func } };
     906                                // strip reference from function
     907                                func2->expr = referenceToRvalueConversion( func->expr, func2->cost );
     908
     909                                // Each argument must be matched with a parameter of the current candidate
     910                                for ( auto & argsList : possibilities ) {
     911                                        try {
     912                                                // Declare data structures needed for resolution
     913                                                ast::OpenVarSet open;
     914                                                ast::AssertionSet need, have;
     915                                                ast::TypeEnvironment resultEnv{ func->env };
     916                                                // Add all type variables as open so that those not used in the
     917                                                // parameter list are still considered open
     918                                                resultEnv.add( funcType->forall );
     919
     920                                                // load type variables from arguments into one shared space
     921                                                for ( auto & arg : argsList ) {
     922                                                        resultEnv.simpleCombine( arg->env );
     923                                                }
     924
     925                                                // Make sure we don't widen any existing bindings
     926                                                resultEnv.forbidWidening();
     927
     928                                                // Find any unbound type variables
     929                                                resultEnv.extractOpenVars( open );
     930
     931                                                auto param = funcType->params.begin();
     932                                                auto paramEnd = funcType->params.end();
     933
     934                                                unsigned n_mutex_param = 0;
     935
     936                                                // For every argument of its set, check if it matches one of the
     937                                                // parameters. The order is important
     938                                                for ( auto & arg : argsList ) {
     939                                                        // Ignore non-mutex arguments
     940                                                        if ( ! nextMutex( param, paramEnd ) ) {
     941                                                                // We ran out of parameters but still have arguments.
     942                                                                // This function doesn't match
     943                                                                SemanticError( stmt->location, funcType,
     944                                                                        toString("candidate function not viable: too many mutex "
     945                                                                        "arguments, expected ", n_mutex_param, "\n" ) );
     946                                                        }
     947
     948                                                        ++n_mutex_param;
     949
     950                                                        // Check if the argument matches the parameter type in the current scope.
     951                                                        // ast::ptr< ast::Type > paramType = (*param)->get_type();
     952
     953                                                        if (
     954                                                                ! unify(
     955                                                                        arg->expr->result, *param, resultEnv, need, have, open )
     956                                                        ) {
     957                                                                // Type doesn't match
     958                                                                stringstream ss;
     959                                                                ss << "candidate function not viable: no known conversion "
     960                                                                        "from '";
     961                                                                ast::print( ss, *param );
     962                                                                ss << "' to '";
     963                                                                ast::print( ss, arg->expr->result );
     964                                                                ss << "' with env '";
     965                                                                ast::print( ss, resultEnv );
     966                                                                ss << "'\n";
     967                                                                SemanticError( stmt->location, funcType, ss.str() );
     968                                                        }
     969
     970                                                        ++param;
     971                                                }
     972
     973                                                // All arguments match!
     974
     975                                                // Check if parameters are missing
     976                                                if ( nextMutex( param, paramEnd ) ) {
     977                                                        do {
     978                                                                ++n_mutex_param;
     979                                                                ++param;
     980                                                        } while ( nextMutex( param, paramEnd ) );
     981
     982                                                        // We ran out of arguments but still have parameters left; this
     983                                                        // function doesn't match
     984                                                        SemanticError( stmt->location, funcType,
     985                                                                toString( "candidate function not viable: too few mutex "
     986                                                                "arguments, expected ", n_mutex_param, "\n" ) );
     987                                                }
     988
     989                                                // All parameters match!
     990
     991                                                // Finish the expressions to tie in proper environments
     992                                                finishExpr( func2->expr, resultEnv );
     993                                                for ( CandidateRef & arg : argsList ) {
     994                                                        finishExpr( arg->expr, resultEnv );
     995                                                }
     996
     997                                                // This is a match, store it and save it for later
     998                                                funcCandidates.emplace_back( std::move( func2 ) );
     999                                                argsCandidates.emplace_back( std::move( argsList ) );
     1000
     1001                                        } catch ( SemanticErrorException & e ) {
     1002                                                errors.append( e );
     1003                                        }
     1004                                }
     1005                        } catch ( SemanticErrorException & e ) {
     1006                                errors.append( e );
     1007                        }
     1008                }
     1009
     1010                // Make sure correct number of arguments
     1011                if( funcCandidates.empty() ) {
     1012                        SemanticErrorException top( stmt->location,
     1013                                "No alternatives for function in call to waitfor" );
     1014                        top.append( errors );
     1015                        throw top;
     1016                }
     1017
     1018                if( argsCandidates.empty() ) {
     1019                        SemanticErrorException top( stmt->location,
     1020                                "No alternatives for arguments in call to waitfor" );
     1021                        top.append( errors );
     1022                        throw top;
     1023                }
     1024
     1025                if( funcCandidates.size() > 1 ) {
     1026                        SemanticErrorException top( stmt->location,
     1027                                "Ambiguous function in call to waitfor" );
     1028                        top.append( errors );
     1029                        throw top;
     1030                }
     1031                if( argsCandidates.size() > 1 ) {
     1032                        SemanticErrorException top( stmt->location,
     1033                                "Ambiguous arguments in call to waitfor" );
     1034                        top.append( errors );
     1035                        throw top;
     1036                }
     1037                // TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.
     1038
     1039                // build new clause
     1040                auto clause2 = new ast::WaitForClause( clause.location );
     1041
     1042                clause2->target = funcCandidates.front()->expr;
     1043
     1044                clause2->target_args.reserve( clause.target_args.size() );
     1045                const ast::StructDecl * decl_monitor = symtab.lookupStruct( "monitor$" );
     1046                for ( auto arg : argsCandidates.front() ) {
     1047                        const auto & loc = stmt->location;
     1048
     1049                        ast::Expr * init = new ast::CastExpr( loc,
     1050                                new ast::UntypedExpr( loc,
     1051                                        new ast::NameExpr( loc, "get_monitor" ),
     1052                                        { arg->expr }
     1053                                ),
     1054                                new ast::PointerType(
     1055                                        new ast::StructInstType(
     1056                                                decl_monitor
     1057                                        )
     1058                                )
     1059                        );
     1060
     1061                        clause2->target_args.emplace_back( findSingleExpression( init, context ) );
     1062                }
     1063
     1064                // Resolve the conditions as if it were an IfStmt, statements normally
     1065                clause2->when_cond = findSingleExpression( clause.when_cond, context );
     1066                clause2->stmt = clause.stmt->accept( *visitor );
     1067
     1068                // set results into stmt
     1069                auto n = mutate( stmt );
     1070                n->clauses[i] = clause2;
     1071                stmt = n;
     1072        }
     1073
     1074        if ( stmt->timeout_stmt ) {
     1075                // resolve the timeout as a size_t, the conditions like IfStmt, and stmts normally
     1076                ast::ptr< ast::Type > target =
     1077                        new ast::BasicType{ ast::BasicType::LongLongUnsignedInt };
     1078                auto timeout_time = findSingleExpression( stmt->timeout_time, target, context );
     1079                auto timeout_cond = findSingleExpression( stmt->timeout_cond, context );
     1080                auto timeout_stmt = stmt->timeout_stmt->accept( *visitor );
     1081
     1082                // set results into stmt
     1083                auto n = mutate( stmt );
     1084                n->timeout_time = std::move( timeout_time );
     1085                n->timeout_cond = std::move( timeout_cond );
     1086                n->timeout_stmt = std::move( timeout_stmt );
     1087                stmt = n;
     1088        }
     1089
     1090        if ( stmt->else_stmt ) {
     1091                // resolve the condition like IfStmt, stmts normally
     1092                auto else_cond = findSingleExpression( stmt->else_cond, context );
     1093                auto else_stmt = stmt->else_stmt->accept( *visitor );
     1094
     1095                // set results into stmt
     1096                auto n = mutate( stmt );
     1097                n->else_cond = std::move( else_cond );
     1098                n->else_stmt = std::move( else_stmt );
     1099                stmt = n;
     1100        }
     1101
     1102        return stmt;
     1103}
     1104
     1105const ast::WithStmt * Resolver::previsit( const ast::WithStmt * withStmt ) {
     1106        auto mutStmt = mutate(withStmt);
     1107        resolveWithExprs(mutStmt->exprs, stmtsToAddBefore);
     1108        return mutStmt;
     1109}
     1110
     1111void Resolver::resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd) {
     1112        for (auto & expr : exprs) {
     1113                // only struct- and union-typed expressions are viable candidates
     1114                expr = findKindExpression( expr, context, structOrUnion, "with expression" );
     1115
     1116                // if with expression might be impure, create a temporary so that it is evaluated once
     1117                if ( Tuples::maybeImpure( expr ) ) {
     1118                        static UniqueName tmpNamer( "_with_tmp_" );
     1119                        const CodeLocation loc = expr->location;
     1120                        auto tmp = new ast::ObjectDecl(loc, tmpNamer.newName(), expr->result, new ast::SingleInit(loc, expr ) );
     1121                        expr = new ast::VariableExpr( loc, tmp );
     1122                        stmtsToAdd.push_back( new ast::DeclStmt(loc, tmp ) );
     1123                        if ( InitTweak::isConstructable( tmp->type ) ) {
     1124                                // generate ctor/dtor and resolve them
     1125                                tmp->init = InitTweak::genCtorInit( loc, tmp );
     1126                        }
     1127                        // since tmp is freshly created, this should modify tmp in-place
     1128                        tmp->accept( *visitor );
     1129                } else if (expr->env && expr->env->empty()) {
     1130                        expr = ast::mutate_field(expr.get(), &ast::Expr::env, nullptr);
     1131                }
     1132        }
     1133}
     1134
     1135const ast::SingleInit * Resolver::previsit( const ast::SingleInit * singleInit ) {
     1136        visit_children = false;
     1137        // resolve initialization using the possibilities as determined by the `currentObject`
     1138        // cursor.
     1139        ast::ptr< ast::Expr > untyped = new ast::UntypedInitExpr{
     1140                singleInit->location, singleInit->value, currentObject.getOptions() };
     1141        ast::ptr<ast::Expr> newExpr = findSingleExpression( untyped, context );
     1142        const ast::InitExpr * initExpr = newExpr.strict_as< ast::InitExpr >();
     1143
     1144        // move cursor to the object that is actually initialized
     1145        currentObject.setNext( initExpr->designation );
     1146
     1147        // discard InitExpr wrapper and retain relevant pieces.
     1148        // `initExpr` may have inferred params in the case where the expression specialized a
     1149        // function pointer, and newExpr may already have inferParams of its own, so a simple
     1150        // swap is not sufficient
     1151        ast::Expr::InferUnion inferred = initExpr->inferred;
     1152        swap_and_save_env( newExpr, initExpr->expr );
     1153        newExpr.get_and_mutate()->inferred.splice( std::move(inferred) );
     1154
     1155        // get the actual object's type (may not exactly match what comes back from the resolver
     1156        // due to conversions)
     1157        const ast::Type * initContext = currentObject.getCurrentType();
     1158
     1159        removeExtraneousCast( newExpr );
     1160
     1161        // check if actual object's type is char[]
     1162        if ( auto at = dynamic_cast< const ast::ArrayType * >( initContext ) ) {
     1163                if ( isCharType( at->base ) ) {
     1164                        // check if the resolved type is char*
     1165                        if ( auto pt = newExpr->result.as< ast::PointerType >() ) {
     1166                                if ( isCharType( pt->base ) ) {
     1167                                        // strip cast if we're initializing a char[] with a char*
     1168                                        // e.g. char x[] = "hello"
     1169                                        if ( auto ce = newExpr.as< ast::CastExpr >() ) {
     1170                                                swap_and_save_env( newExpr, ce->arg );
    671171                                        }
    681172                                }
    691173                        }
    70                 };
    71 
    72                 struct ResolveDesignators final : public ast::WithShortCircuiting {
    73                         ResolveContext& context;
    74                         bool result = false;
    75 
    76                         ResolveDesignators( ResolveContext& _context ): context{_context} {};
    77 
    78                         void previsit( const ast::Node * ) {
    79                                 // short circuit if we already know there are designations
    80                                 if ( result ) visit_children = false;
    81                         }
    82 
    83                         void previsit( const ast::Designation * des ) {
    84                                 if ( result ) visit_children = false;
    85                                 else if ( ! des->designators.empty() ) {
    86                                         if ( (des->designators.size() == 1) ) {
    87                                                 const ast::Expr * designator = des->designators.at(0);
    88                                                 if ( const ast::NameExpr * designatorName = dynamic_cast<const ast::NameExpr *>(designator) ) {
    89                                                         auto candidates = context.symtab.lookupId(designatorName->name);
    90                                                         for ( auto candidate : candidates ) {
    91                                                                 if ( dynamic_cast<const ast::EnumInstType *>(candidate.id->get_type()) ) {
    92                                                                         result = true;
    93                                                                         break;
    94                                                                 }
    95                                                         }
    96                                                 }
    97                                         }
    98                                         visit_children = false;
    99                                 }
    100                         }
    101                 };
    102         } // anonymous namespace
    103         /// Check if this expression is or includes a deleted expression
    104         const ast::DeletedExpr * findDeletedExpr( const ast::Expr * expr ) {
    105                 return ast::Pass<DeleteFinder>::read( expr );
    106         }
    107 
    108         namespace {
    109                 /// always-accept candidate filter
    110                 bool anyCandidate( const Candidate & ) { return true; }
    111 
    112                 /// Calls the CandidateFinder and finds the single best candidate
    113                 CandidateRef findUnfinishedKindExpression(
    114                         const ast::Expr * untyped, const ResolveContext & context, const std::string & kind,
    115                         std::function<bool(const Candidate &)> pred = anyCandidate, ResolveMode mode = {}
    116                 ) {
    117                         if ( ! untyped ) return nullptr;
    118 
    119                         // xxx - this isn't thread-safe, but should work until we parallelize the resolver
    120                         static unsigned recursion_level = 0;
    121 
    122                         ++recursion_level;
    123                         ast::TypeEnvironment env;
    124                         CandidateFinder finder( context, env );
    125                         finder.allowVoid = true;
    126                         finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode );
    127                         --recursion_level;
    128 
    129                         // produce a filtered list of candidates
    130                         CandidateList candidates;
    131                         for ( auto & cand : finder.candidates ) {
    132                                 if ( pred( *cand ) ) { candidates.emplace_back( cand ); }
    133                         }
    134 
    135                         // produce invalid error if no candidates
    136                         if ( candidates.empty() ) {
    137                                 SemanticError( untyped,
    138                                         toString( "No reasonable alternatives for ", kind, (kind != "" ? " " : ""),
    139                                         "expression: ") );
    140                         }
    141 
    142                         // search for cheapest candidate
    143                         CandidateList winners;
    144                         bool seen_undeleted = false;
    145                         for ( CandidateRef & cand : candidates ) {
    146                                 int c = winners.empty() ? -1 : cand->cost.compare( winners.front()->cost );
    147 
    148                                 if ( c > 0 ) continue;  // skip more expensive than winner
    149 
    150                                 if ( c < 0 ) {
    151                                         // reset on new cheapest
    152                                         seen_undeleted = ! findDeletedExpr( cand->expr );
    153                                         winners.clear();
    154                                 } else /* if ( c == 0 ) */ {
    155                                         if ( findDeletedExpr( cand->expr ) ) {
    156                                                 // skip deleted expression if already seen one equivalent-cost not
    157                                                 if ( seen_undeleted ) continue;
    158                                         } else if ( ! seen_undeleted ) {
    159                                                 // replace list of equivalent-cost deleted expressions with one non-deleted
    160                                                 winners.clear();
    161                                                 seen_undeleted = true;
    162                                         }
    163                                 }
    164 
    165                                 winners.emplace_back( std::move( cand ) );
    166                         }
    167 
    168                         // promote candidate.cvtCost to .cost
    169                         // promoteCvtCost( winners );
    170 
    171                         // produce ambiguous errors, if applicable
    172                         if ( winners.size() != 1 ) {
    173                                 std::ostringstream stream;
    174                                 stream << "Cannot choose between " << winners.size() << " alternatives for "
    175                                         << kind << (kind != "" ? " " : "") << "expression\n";
    176                                 ast::print( stream, untyped );
    177                                 stream << " Alternatives are:\n";
    178                                 print( stream, winners, 1 );
    179                                 SemanticError( untyped->location, stream.str() );
    180                         }
    181 
    182                         // single selected choice
    183                         CandidateRef & choice = winners.front();
    184 
    185                         // fail on only expression deleted
    186                         if ( ! seen_undeleted ) {
    187                                 SemanticError( untyped->location, choice->expr.get(), "Unique best alternative "
    188                                 "includes deleted identifier in " );
    189                         }
    190 
    191                         return std::move( choice );
    192                 }
    193 
    194                 /// Strips extraneous casts out of an expression
    195                 struct StripCasts final {
    196                         const ast::Expr * postvisit( const ast::CastExpr * castExpr ) {
    197                                 if (
    198                                         castExpr->isGenerated == ast::GeneratedCast
    199                                         && typesCompatible( castExpr->arg->result, castExpr->result )
    200                                 ) {
    201                                         // generated cast is the same type as its argument, remove it after keeping env
    202                                         return ast::mutate_field(
    203                                                 castExpr->arg.get(), &ast::Expr::env, castExpr->env );
    204                                 }
    205                                 return castExpr;
    206                         }
    207 
    208                         static void strip( ast::ptr< ast::Expr > & expr ) {
    209                                 ast::Pass< StripCasts > stripper;
    210                                 expr = expr->accept( stripper );
    211                         }
    212                 };
    213 
    214                 /// Swaps argument into expression pointer, saving original environment
    215                 void swap_and_save_env( ast::ptr< ast::Expr > & expr, const ast::Expr * newExpr ) {
    216                         ast::ptr< ast::TypeSubstitution > env = expr->env;
    217                         expr.set_and_mutate( newExpr )->env = env;
    218                 }
    219 
    220                 /// Removes cast to type of argument (unlike StripCasts, also handles non-generated casts)
    221                 void removeExtraneousCast( ast::ptr<ast::Expr> & expr ) {
    222                         if ( const ast::CastExpr * castExpr = expr.as< ast::CastExpr >() ) {
    223                                 if ( typesCompatible( castExpr->arg->result, castExpr->result ) ) {
    224                                         // cast is to the same type as its argument, remove it
    225                                         swap_and_save_env( expr, castExpr->arg );
    226                                 }
    227                         }
    228                 }
    229 
    230 
    231         } // anonymous namespace
    232 /// Establish post-resolver invariants for expressions
    233                 void finishExpr(
    234                         ast::ptr< ast::Expr > & expr, const ast::TypeEnvironment & env,
    235                         const ast::TypeSubstitution * oldenv = nullptr
    236                 ) {
    237                         // set up new type substitution for expression
    238                         ast::ptr< ast::TypeSubstitution > newenv =
    239                                  oldenv ? oldenv : new ast::TypeSubstitution{};
    240                         env.writeToSubstitution( *newenv.get_and_mutate() );
    241                         expr.get_and_mutate()->env = std::move( newenv );
    242                         // remove unncecessary casts
    243                         StripCasts::strip( expr );
    244                 }
    245 
    246         ast::ptr< ast::Expr > resolveInVoidContext(
    247                 const ast::Expr * expr, const ResolveContext & context,
    248                 ast::TypeEnvironment & env
    249         ) {
    250                 assertf( expr, "expected a non-null expression" );
    251 
    252                 // set up and resolve expression cast to void
    253                 ast::ptr< ast::CastExpr > untyped = new ast::CastExpr{ expr };
    254                 CandidateRef choice = findUnfinishedKindExpression(
    255                         untyped, context, "", anyCandidate, ResolveMode::withAdjustment() );
    256 
    257                 // a cast expression has either 0 or 1 interpretations (by language rules);
    258                 // if 0, an exception has already been thrown, and this code will not run
    259                 const ast::CastExpr * castExpr = choice->expr.strict_as< ast::CastExpr >();
    260                 env = std::move( choice->env );
    261 
    262                 return castExpr->arg;
    263         }
    264 
    265         /// Resolve `untyped` to the expression whose candidate is the best match for a `void`
    266                 /// context.
    267                 ast::ptr< ast::Expr > findVoidExpression(
    268                         const ast::Expr * untyped, const ResolveContext & context
    269                 ) {
    270                         ast::TypeEnvironment env;
    271                         ast::ptr< ast::Expr > newExpr = resolveInVoidContext( untyped, context, env );
    272                         finishExpr( newExpr, env, untyped->env );
    273                         return newExpr;
    274                 }
    275 
    276         namespace {
    277 
    278 
    279                 /// resolve `untyped` to the expression whose candidate satisfies `pred` with the
    280                 /// lowest cost, returning the resolved version
    281                 ast::ptr< ast::Expr > findKindExpression(
    282                         const ast::Expr * untyped, const ResolveContext & context,
    283                         std::function<bool(const Candidate &)> pred = anyCandidate,
    284                         const std::string & kind = "", ResolveMode mode = {}
    285                 ) {
    286                         if ( ! untyped ) return {};
    287                         CandidateRef choice =
    288                                 findUnfinishedKindExpression( untyped, context, kind, pred, mode );
    289                         ResolvExpr::finishExpr( choice->expr, choice->env, untyped->env );
    290                         return std::move( choice->expr );
    291                 }
    292 
    293                 /// Resolve `untyped` to the single expression whose candidate is the best match
    294                 ast::ptr< ast::Expr > findSingleExpression(
    295                         const ast::Expr * untyped, const ResolveContext & context
    296                 ) {
    297                         Stats::ResolveTime::start( untyped );
    298                         auto res = findKindExpression( untyped, context );
    299                         Stats::ResolveTime::stop();
    300                         return res;
    301                 }
    302         } // anonymous namespace
    303 
    304         ast::ptr< ast::Expr > findSingleExpression(
    305                 const ast::Expr * untyped, const ast::Type * type,
    306                 const ResolveContext & context
    307         ) {
    308                 assert( untyped && type );
    309                 ast::ptr< ast::Expr > castExpr = new ast::CastExpr{ untyped, type };
    310                 ast::ptr< ast::Expr > newExpr = findSingleExpression( castExpr, context );
    311                 removeExtraneousCast( newExpr );
    312                 return newExpr;
    313         }
    314 
    315         namespace {
    316                 bool structOrUnion( const Candidate & i ) {
    317                         const ast::Type * t = i.expr->result->stripReferences();
    318                         return dynamic_cast< const ast::StructInstType * >( t ) || dynamic_cast< const ast::UnionInstType * >( t );
    319                 }
    320                 /// Predicate for "Candidate has integral type"
    321                 bool hasIntegralType( const Candidate & i ) {
    322                         const ast::Type * type = i.expr->result;
    323 
    324                         if ( auto bt = dynamic_cast< const ast::BasicType * >( type ) ) {
    325                                 return bt->isInteger();
    326                         } else if (
    327                                 dynamic_cast< const ast::EnumInstType * >( type )
    328                                 || dynamic_cast< const ast::ZeroType * >( type )
    329                                 || dynamic_cast< const ast::OneType * >( type )
    330                         ) {
    331                                 return true;
    332                         } else return false;
    333                 }
    334 
    335                 /// Resolve `untyped` as an integral expression, returning the resolved version
    336                 ast::ptr< ast::Expr > findIntegralExpression(
    337                         const ast::Expr * untyped, const ResolveContext & context
    338                 ) {
    339                         return findKindExpression( untyped, context, hasIntegralType, "condition" );
    340                 }
    341 
    342                 /// check if a type is a character type
    343                 bool isCharType( const ast::Type * t ) {
    344                         if ( auto bt = dynamic_cast< const ast::BasicType * >( t ) ) {
    345                                 return bt->kind == ast::BasicType::Char
    346                                         || bt->kind == ast::BasicType::SignedChar
    347                                         || bt->kind == ast::BasicType::UnsignedChar;
    348                         }
     1174                }
     1175        }
     1176
     1177        // move cursor to next object in preparation for next initializer
     1178        currentObject.increment();
     1179
     1180        // set initializer expression to resolved expression
     1181        return ast::mutate_field( singleInit, &ast::SingleInit::value, std::move(newExpr) );
     1182}
     1183
     1184const ast::ListInit * Resolver::previsit( const ast::ListInit * listInit ) {
     1185        // move cursor into brace-enclosed initializer-list
     1186        currentObject.enterListInit( listInit->location );
     1187
     1188        assert( listInit->designations.size() == listInit->initializers.size() );
     1189        for ( unsigned i = 0; i < listInit->designations.size(); ++i ) {
     1190                // iterate designations and initializers in pairs, moving the cursor to the current
     1191                // designated object and resolving the initializer against that object
     1192                listInit = ast::mutate_field_index(
     1193                        listInit, &ast::ListInit::designations, i,
     1194                        currentObject.findNext( listInit->designations[i] ) );
     1195                listInit = ast::mutate_field_index(
     1196                        listInit, &ast::ListInit::initializers, i,
     1197                        listInit->initializers[i]->accept( *visitor ) );
     1198        }
     1199
     1200        // move cursor out of brace-enclosed initializer-list
     1201        currentObject.exitListInit();
     1202
     1203        visit_children = false;
     1204        return listInit;
     1205}
     1206
     1207const ast::ConstructorInit * Resolver::previsit( const ast::ConstructorInit * ctorInit ) {
     1208        visitor->maybe_accept( ctorInit, &ast::ConstructorInit::ctor );
     1209        visitor->maybe_accept( ctorInit, &ast::ConstructorInit::dtor );
     1210
     1211        // found a constructor - can get rid of C-style initializer
     1212        // xxx - Rob suggests this field is dead code
     1213        ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::init, nullptr );
     1214
     1215        // intrinsic single-parameter constructors and destructors do nothing. Since this was
     1216        // implicitly generated, there's no way for it to have side effects, so get rid of it to
     1217        // clean up generated code
     1218        if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) {
     1219                ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::ctor, nullptr );
     1220        }
     1221        if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->dtor ) ) {
     1222                ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::dtor, nullptr );
     1223        }
     1224
     1225        return ctorInit;
     1226}
     1227
     1228// suppress error on autogen functions and mark invalid autogen as deleted.
     1229bool Resolver::on_error(ast::ptr<ast::Decl> & decl) {
     1230        if (auto functionDecl = decl.as<ast::FunctionDecl>()) {
     1231                // xxx - can intrinsic gen ever fail?
     1232                if (functionDecl->linkage == ast::Linkage::AutoGen) {
     1233                        auto mutDecl = mutate(functionDecl);
     1234                        mutDecl->isDeleted = true;
     1235                        mutDecl->stmts = nullptr;
     1236                        decl = mutDecl;
    3491237                        return false;
    3501238                }
    351 
    352                 /// Advance a type itertor to the next mutex parameter
    353                 template<typename Iter>
    354                 inline bool nextMutex( Iter & it, const Iter & end ) {
    355                         while ( it != end && ! (*it)->is_mutex() ) { ++it; }
    356                         return it != end;
    357                 }
    358         }
    359 
    360         class Resolver final
    361         : public ast::WithSymbolTable, public ast::WithGuards,
    362           public ast::WithVisitorRef<Resolver>, public ast::WithShortCircuiting,
    363           public ast::WithStmtsToAdd<> {
    364 
    365                 ast::ptr< ast::Type > functionReturn = nullptr;
    366                 ast::CurrentObject currentObject;
    367                 // for work previously in GenInit
    368                 static InitTweak::ManagedTypes managedTypes;
    369                 ResolveContext context;
    370 
    371                 bool inEnumDecl = false;
    372 
    373         public:
    374                 static size_t traceId;
    375                 Resolver( const ast::TranslationGlobal & global ) :
    376                         ast::WithSymbolTable(ast::SymbolTable::ErrorDetection::ValidateOnAdd),
    377                         context{ symtab, global } {}
    378                 Resolver( const ResolveContext & context ) :
    379                         ast::WithSymbolTable{ context.symtab },
    380                         context{ symtab, context.global } {}
    381 
    382                 const ast::FunctionDecl * previsit( const ast::FunctionDecl * );
    383                 const ast::FunctionDecl * postvisit( const ast::FunctionDecl * );
    384                 const ast::ObjectDecl * previsit( const ast::ObjectDecl * );
    385                 void previsit( const ast::AggregateDecl * );
    386                 void previsit( const ast::StructDecl * );
    387                 void previsit( const ast::EnumDecl * );
    388                 const ast::StaticAssertDecl * previsit( const ast::StaticAssertDecl * );
    389 
    390                 const ast::ArrayType * previsit( const ast::ArrayType * );
    391                 const ast::PointerType * previsit( const ast::PointerType * );
    392 
    393                 const ast::ExprStmt *        previsit( const ast::ExprStmt * );
    394                 const ast::AsmExpr *         previsit( const ast::AsmExpr * );
    395                 const ast::AsmStmt *         previsit( const ast::AsmStmt * );
    396                 const ast::IfStmt *          previsit( const ast::IfStmt * );
    397                 const ast::WhileDoStmt *     previsit( const ast::WhileDoStmt * );
    398                 const ast::ForStmt *         previsit( const ast::ForStmt * );
    399                 const ast::SwitchStmt *      previsit( const ast::SwitchStmt * );
    400                 const ast::CaseClause *      previsit( const ast::CaseClause * );
    401                 const ast::BranchStmt *      previsit( const ast::BranchStmt * );
    402                 const ast::ReturnStmt *      previsit( const ast::ReturnStmt * );
    403                 const ast::ThrowStmt *       previsit( const ast::ThrowStmt * );
    404                 const ast::CatchClause *     previsit( const ast::CatchClause * );
    405                 const ast::CatchClause *     postvisit( const ast::CatchClause * );
    406                 const ast::WaitForStmt *     previsit( const ast::WaitForStmt * );
    407                 const ast::WithStmt *        previsit( const ast::WithStmt * );
    408 
    409                 const ast::SingleInit *      previsit( const ast::SingleInit * );
    410                 const ast::ListInit *        previsit( const ast::ListInit * );
    411                 const ast::ConstructorInit * previsit( const ast::ConstructorInit * );
    412 
    413                 void resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd);
    414 
    415                 void beginScope() { managedTypes.beginScope(); }
    416                 void endScope() { managedTypes.endScope(); }
    417                 bool on_error(ast::ptr<ast::Decl> & decl);
    418         };
    419         // size_t Resolver::traceId = Stats::Heap::new_stacktrace_id("Resolver");
    420 
    421         InitTweak::ManagedTypes Resolver::managedTypes;
    422 
    423         void resolve( ast::TranslationUnit& translationUnit ) {
    424                 ast::Pass< Resolver >::run( translationUnit, translationUnit.global );
    425         }
    426 
    427         ast::ptr< ast::Init > resolveCtorInit(
    428                 const ast::ConstructorInit * ctorInit, const ResolveContext & context
    429         ) {
    430                 assert( ctorInit );
    431                 ast::Pass< Resolver > resolver( context );
    432                 return ctorInit->accept( resolver );
    433         }
    434 
    435         const ast::Expr * resolveStmtExpr(
    436                 const ast::StmtExpr * stmtExpr, const ResolveContext & context
    437         ) {
    438                 assert( stmtExpr );
    439                 ast::Pass< Resolver > resolver( context );
    440                 auto ret = mutate(stmtExpr->accept(resolver));
    441                 strict_dynamic_cast< ast::StmtExpr * >( ret )->computeResult();
    442                 return ret;
    443         }
    444 
    445         namespace {
    446                 const ast::Attribute * handleAttribute(const CodeLocation & loc, const ast::Attribute * attr, const ResolveContext & context) {
    447                         std::string name = attr->normalizedName();
    448                         if (name == "constructor" || name == "destructor") {
    449                                 if (attr->params.size() == 1) {
    450                                         auto arg = attr->params.front();
    451                                         auto resolved = ResolvExpr::findSingleExpression( arg, new ast::BasicType( ast::BasicType::LongLongSignedInt ), context );
    452                                         auto result = eval(arg);
    453 
    454                                         auto mutAttr = mutate(attr);
    455                                         mutAttr->params.front() = resolved;
    456                                         if (! result.hasKnownValue) {
    457                                                 SemanticWarning(loc, Warning::GccAttributes,
    458                                                         toCString( name, " priorities must be integers from 0 to 65535 inclusive: ", arg ) );
    459                                         }
    460                                         else {
    461                                                 auto priority = result.knownValue;
    462                                                 if (priority < 101) {
    463                                                         SemanticWarning(loc, Warning::GccAttributes,
    464                                                                 toCString( name, " priorities from 0 to 100 are reserved for the implementation" ) );
    465                                                 } else if (priority < 201 && ! buildingLibrary()) {
    466                                                         SemanticWarning(loc, Warning::GccAttributes,
    467                                                                 toCString( name, " priorities from 101 to 200 are reserved for the implementation" ) );
    468                                                 }
    469                                         }
    470                                         return mutAttr;
    471                                 } else if (attr->params.size() > 1) {
    472                                         SemanticWarning(loc, Warning::GccAttributes, toCString( "too many arguments to ", name, " attribute" ) );
    473                                 } else {
    474                                         SemanticWarning(loc, Warning::GccAttributes, toCString( "too few arguments to ", name, " attribute" ) );
    475                                 }
    476                         }
    477                         return attr;
    478                 }
    479         }
    480 
    481         const ast::FunctionDecl * Resolver::previsit( const ast::FunctionDecl * functionDecl ) {
    482                 GuardValue( functionReturn );
    483 
    484                 assert (functionDecl->unique());
    485                 if (!functionDecl->has_body() && !functionDecl->withExprs.empty()) {
    486                         SemanticError(functionDecl->location, functionDecl, "Function without body has with declarations");
    487                 }
    488 
    489                 if (!functionDecl->isTypeFixed) {
    490                         auto mutDecl = mutate(functionDecl);
    491                         auto mutType = mutDecl->type.get_and_mutate();
    492 
    493                         for (auto & attr: mutDecl->attributes) {
    494                                 attr = handleAttribute(mutDecl->location, attr, context );
    495                         }
    496 
    497                         // handle assertions
    498 
    499                         symtab.enterScope();
    500                         mutType->forall.clear();
    501                         mutType->assertions.clear();
    502                         for (auto & typeParam : mutDecl->type_params) {
    503                                 symtab.addType(typeParam);
    504                                 mutType->forall.emplace_back(new ast::TypeInstType(typeParam));
    505                         }
    506                         for (auto & asst : mutDecl->assertions) {
    507                                 asst = fixObjectType(asst.strict_as<ast::ObjectDecl>(), context);
    508                                 symtab.addId(asst);
    509                                 mutType->assertions.emplace_back(new ast::VariableExpr(functionDecl->location, asst));
    510                         }
    511 
    512                         // temporarily adds params to symbol table.
    513                         // actual scoping rules for params and withexprs differ - see Pass::visit(FunctionDecl)
    514 
    515                         std::vector<ast::ptr<ast::Type>> paramTypes;
    516                         std::vector<ast::ptr<ast::Type>> returnTypes;
    517 
    518                         for (auto & param : mutDecl->params) {
    519                                 param = fixObjectType(param.strict_as<ast::ObjectDecl>(), context);
    520                                 symtab.addId(param);
    521                                 paramTypes.emplace_back(param->get_type());
    522                         }
    523                         for (auto & ret : mutDecl->returns) {
    524                                 ret = fixObjectType(ret.strict_as<ast::ObjectDecl>(), context);
    525                                 returnTypes.emplace_back(ret->get_type());
    526                         }
    527                         // since function type in decl is just a view of param types, need to update that as well
    528                         mutType->params = std::move(paramTypes);
    529                         mutType->returns = std::move(returnTypes);
    530 
    531                         auto renamedType = strict_dynamic_cast<const ast::FunctionType *>(renameTyVars(mutType, RenameMode::GEN_EXPR_ID));
    532 
    533                         std::list<ast::ptr<ast::Stmt>> newStmts;
    534                         resolveWithExprs (mutDecl->withExprs, newStmts);
    535 
    536                         if (mutDecl->stmts) {
    537                                 auto mutStmt = mutDecl->stmts.get_and_mutate();
    538                                 mutStmt->kids.splice(mutStmt->kids.begin(), std::move(newStmts));
    539                                 mutDecl->stmts = mutStmt;
    540                         }
    541 
    542                         symtab.leaveScope();
    543 
    544                         mutDecl->type = renamedType;
    545                         mutDecl->mangleName = Mangle::mangle(mutDecl);
    546                         mutDecl->isTypeFixed = true;
    547                         functionDecl = mutDecl;
    548                 }
    549                 managedTypes.handleDWT(functionDecl);
    550 
    551                 functionReturn = extractResultType( functionDecl->type );
    552                 return functionDecl;
    553         }
    554 
    555         const ast::FunctionDecl * Resolver::postvisit( const ast::FunctionDecl * functionDecl ) {
    556                 // default value expressions have an environment which shouldn't be there and trips up
    557                 // later passes.
    558                 assert( functionDecl->unique() );
    559                 ast::FunctionType * mutType = mutate( functionDecl->type.get() );
    560 
    561                 for ( unsigned i = 0 ; i < mutType->params.size() ; ++i ) {
    562                         if ( const ast::ObjectDecl * obj = mutType->params[i].as< ast::ObjectDecl >() ) {
    563                                 if ( const ast::SingleInit * init = obj->init.as< ast::SingleInit >() ) {
    564                                         if ( init->value->env == nullptr ) continue;
    565                                         // clone initializer minus the initializer environment
    566                                         auto mutParam = mutate( mutType->params[i].strict_as< ast::ObjectDecl >() );
    567                                         auto mutInit = mutate( mutParam->init.strict_as< ast::SingleInit >() );
    568                                         auto mutValue = mutate( mutInit->value.get() );
    569 
    570                                         mutValue->env = nullptr;
    571                                         mutInit->value = mutValue;
    572                                         mutParam->init = mutInit;
    573                                         mutType->params[i] = mutParam;
    574 
    575                                         assert( ! mutType->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env);
    576                                 }
    577                         }
    578                 }
    579                 mutate_field(functionDecl, &ast::FunctionDecl::type, mutType);
    580                 return functionDecl;
    581         }
    582 
    583         const ast::ObjectDecl * Resolver::previsit( const ast::ObjectDecl * objectDecl ) {
    584                 // To handle initialization of routine pointers [e.g. int (*fp)(int) = foo()],
    585                 // class-variable `initContext` is changed multiple times because the LHS is analyzed
    586                 // twice. The second analysis changes `initContext` because a function type can contain
    587                 // object declarations in the return and parameter types. Therefore each value of
    588                 // `initContext` is retained so the type on the first analysis is preserved and used for
    589                 // selecting the RHS.
    590                 GuardValue( currentObject );
    591 
    592                 if ( inEnumDecl && dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() ) ) {
    593                         // enumerator initializers should not use the enum type to initialize, since the
    594                         // enum type is still incomplete at this point. Use `int` instead.
    595 
    596                         if ( auto enumBase = dynamic_cast< const ast::EnumInstType * >
    597                                 ( objectDecl->get_type() )->base->base ) {
    598                                 objectDecl = fixObjectType( objectDecl, context );
    599                                 currentObject = ast::CurrentObject{
    600                                         objectDecl->location,
    601                                         enumBase
    602                                 };
    603                         } else {
    604                                 objectDecl = fixObjectType( objectDecl, context );
    605                                 currentObject = ast::CurrentObject{
    606                                         objectDecl->location, new ast::BasicType{ ast::BasicType::SignedInt } };
    607                         }
    608 
    609                 }
    610                 else {
    611                         if ( !objectDecl->isTypeFixed ) {
    612                                 auto newDecl = fixObjectType(objectDecl, context);
    613                                 auto mutDecl = mutate(newDecl);
    614 
    615                                 // generate CtorInit wrapper when necessary.
    616                                 // in certain cases, fixObjectType is called before reaching
    617                                 // this object in visitor pass, thus disabling CtorInit codegen.
    618                                 // this happens on aggregate members and function parameters.
    619                                 if ( InitTweak::tryConstruct( mutDecl ) && ( managedTypes.isManaged( mutDecl ) || ((! isInFunction() || mutDecl->storage.is_static ) && ! InitTweak::isConstExpr( mutDecl->init ) ) ) ) {
    620                                         // constructed objects cannot be designated
    621                                         if ( InitTweak::isDesignated( mutDecl->init ) ) {
    622                                                 ast::Pass<ResolveDesignators> res( context );
    623                                                 maybe_accept( mutDecl->init.get(), res );
    624                                                 if ( !res.core.result ) {
    625                                                         SemanticError( mutDecl, "Cannot include designations in the initializer for a managed Object.\n"
    626                                                                                    "If this is really what you want, initialize with @=." );
    627                                                 }
    628                                         }
    629                                         // constructed objects should not have initializers nested too deeply
    630                                         if ( ! InitTweak::checkInitDepth( mutDecl ) ) SemanticError( mutDecl, "Managed object's initializer is too deep " );
    631 
    632                                         mutDecl->init = InitTweak::genCtorInit( mutDecl->location, mutDecl );
    633                                 }
    634 
    635                                 objectDecl = mutDecl;
    636                         }
    637                         currentObject = ast::CurrentObject{ objectDecl->location, objectDecl->get_type() };
    638                 }
    639 
    640                 return objectDecl;
    641         }
    642 
    643         void Resolver::previsit( const ast::AggregateDecl * _aggDecl ) {
    644                 auto aggDecl = mutate(_aggDecl);
    645                 assertf(aggDecl == _aggDecl, "type declarations must be unique");
    646 
    647                 for (auto & member: aggDecl->members) {
    648                         // nested type decls are hoisted already. no need to do anything
    649                         if (auto obj = member.as<ast::ObjectDecl>()) {
    650                                 member = fixObjectType(obj, context);
    651                         }
    652                 }
    653         }
    654 
    655         void Resolver::previsit( const ast::StructDecl * structDecl ) {
    656                 previsit(static_cast<const ast::AggregateDecl *>(structDecl));
    657                 managedTypes.handleStruct(structDecl);
    658         }
    659 
    660         void Resolver::previsit( const ast::EnumDecl * ) {
    661                 // in case we decide to allow nested enums
    662                 GuardValue( inEnumDecl );
    663                 inEnumDecl = true;
    664                 // don't need to fix types for enum fields
    665         }
    666 
    667         const ast::StaticAssertDecl * Resolver::previsit(
    668                 const ast::StaticAssertDecl * assertDecl
    669         ) {
    670                 return ast::mutate_field(
    671                         assertDecl, &ast::StaticAssertDecl::cond,
    672                         findIntegralExpression( assertDecl->cond, context ) );
    673         }
    674 
    675         template< typename PtrType >
    676         const PtrType * handlePtrType( const PtrType * type, const ResolveContext & context ) {
    677                 if ( type->dimension ) {
    678                         const ast::Type * sizeType = context.global.sizeType.get();
    679                         ast::ptr< ast::Expr > dimension = findSingleExpression( type->dimension, sizeType, context );
    680                         assertf(dimension->env->empty(), "array dimension expr has nonempty env");
    681                         dimension.get_and_mutate()->env = nullptr;
    682                         ast::mutate_field( type, &PtrType::dimension, dimension );
    683                 }
    684                 return type;
    685         }
    686 
    687         const ast::ArrayType * Resolver::previsit( const ast::ArrayType * at ) {
    688                 return handlePtrType( at, context );
    689         }
    690 
    691         const ast::PointerType * Resolver::previsit( const ast::PointerType * pt ) {
    692                 return handlePtrType( pt, context );
    693         }
    694 
    695         const ast::ExprStmt * Resolver::previsit( const ast::ExprStmt * exprStmt ) {
    696                 visit_children = false;
    697                 assertf( exprStmt->expr, "ExprStmt has null expression in resolver" );
    698 
    699                 return ast::mutate_field(
    700                         exprStmt, &ast::ExprStmt::expr, findVoidExpression( exprStmt->expr, context ) );
    701         }
    702 
    703         const ast::AsmExpr * Resolver::previsit( const ast::AsmExpr * asmExpr ) {
    704                 visit_children = false;
    705 
    706                 asmExpr = ast::mutate_field(
    707                         asmExpr, &ast::AsmExpr::operand, findVoidExpression( asmExpr->operand, context ) );
    708 
    709                 return asmExpr;
    710         }
    711 
    712         const ast::AsmStmt * Resolver::previsit( const ast::AsmStmt * asmStmt ) {
    713                 visitor->maybe_accept( asmStmt, &ast::AsmStmt::input );
    714                 visitor->maybe_accept( asmStmt, &ast::AsmStmt::output );
    715                 visit_children = false;
    716                 return asmStmt;
    717         }
    718 
    719         const ast::IfStmt * Resolver::previsit( const ast::IfStmt * ifStmt ) {
    720                 return ast::mutate_field(
    721                         ifStmt, &ast::IfStmt::cond, findIntegralExpression( ifStmt->cond, context ) );
    722         }
    723 
    724         const ast::WhileDoStmt * Resolver::previsit( const ast::WhileDoStmt * whileDoStmt ) {
    725                 return ast::mutate_field(
    726                         whileDoStmt, &ast::WhileDoStmt::cond, findIntegralExpression( whileDoStmt->cond, context ) );
    727         }
    728 
    729         const ast::ForStmt * Resolver::previsit( const ast::ForStmt * forStmt ) {
    730                 if ( forStmt->cond ) {
    731                         forStmt = ast::mutate_field(
    732                                 forStmt, &ast::ForStmt::cond, findIntegralExpression( forStmt->cond, context ) );
    733                 }
    734 
    735                 if ( forStmt->inc ) {
    736                         forStmt = ast::mutate_field(
    737                                 forStmt, &ast::ForStmt::inc, findVoidExpression( forStmt->inc, context ) );
    738                 }
    739 
    740                 return forStmt;
    741         }
    742 
    743         const ast::SwitchStmt * Resolver::previsit( const ast::SwitchStmt * switchStmt ) {
    744                 GuardValue( currentObject );
    745                 switchStmt = ast::mutate_field(
    746                         switchStmt, &ast::SwitchStmt::cond,
    747                         findIntegralExpression( switchStmt->cond, context ) );
    748                 currentObject = ast::CurrentObject{ switchStmt->location, switchStmt->cond->result };
    749                 return switchStmt;
    750         }
    751 
    752         const ast::CaseClause * Resolver::previsit( const ast::CaseClause * caseStmt ) {
    753                 if ( caseStmt->cond ) {
    754                         std::deque< ast::InitAlternative > initAlts = currentObject.getOptions();
    755                         assertf( initAlts.size() == 1, "SwitchStmt did not correctly resolve an integral "
    756                                 "expression." );
    757 
    758                         ast::ptr< ast::Expr > untyped =
    759                                 new ast::CastExpr{ caseStmt->location, caseStmt->cond, initAlts.front().type };
    760                         ast::ptr< ast::Expr > newExpr = findSingleExpression( untyped, context );
    761 
    762                         // case condition cannot have a cast in C, so it must be removed here, regardless of
    763                         // whether it would perform a conversion.
    764                         if ( const ast::CastExpr * castExpr = newExpr.as< ast::CastExpr >() ) {
    765                                 swap_and_save_env( newExpr, castExpr->arg );
    766                         }
    767 
    768                         caseStmt = ast::mutate_field( caseStmt, &ast::CaseClause::cond, newExpr );
    769                 }
    770                 return caseStmt;
    771         }
    772 
    773         const ast::BranchStmt * Resolver::previsit( const ast::BranchStmt * branchStmt ) {
    774                 visit_children = false;
    775                 // must resolve the argument of a computed goto
    776                 if ( branchStmt->kind == ast::BranchStmt::Goto && branchStmt->computedTarget ) {
    777                         // computed goto argument is void*
    778                         ast::ptr< ast::Type > target = new ast::PointerType{ new ast::VoidType{} };
    779                         branchStmt = ast::mutate_field(
    780                                 branchStmt, &ast::BranchStmt::computedTarget,
    781                                 findSingleExpression( branchStmt->computedTarget, target, context ) );
    782                 }
    783                 return branchStmt;
    784         }
    785 
    786         const ast::ReturnStmt * Resolver::previsit( const ast::ReturnStmt * returnStmt ) {
    787                 visit_children = false;
    788                 if ( returnStmt->expr ) {
    789                         returnStmt = ast::mutate_field(
    790                                 returnStmt, &ast::ReturnStmt::expr,
    791                                 findSingleExpression( returnStmt->expr, functionReturn, context ) );
    792                 }
    793                 return returnStmt;
    794         }
    795 
    796         const ast::ThrowStmt * Resolver::previsit( const ast::ThrowStmt * throwStmt ) {
    797                 visit_children = false;
    798                 if ( throwStmt->expr ) {
    799                         const ast::StructDecl * exceptionDecl =
    800                                 symtab.lookupStruct( "__cfaehm_base_exception_t" );
    801                         assert( exceptionDecl );
    802                         ast::ptr< ast::Type > exceptType =
    803                                 new ast::PointerType{ new ast::StructInstType{ exceptionDecl } };
    804                         throwStmt = ast::mutate_field(
    805                                 throwStmt, &ast::ThrowStmt::expr,
    806                                 findSingleExpression( throwStmt->expr, exceptType, context ) );
    807                 }
    808                 return throwStmt;
    809         }
    810 
    811         const ast::CatchClause * Resolver::previsit( const ast::CatchClause * catchClause ) {
    812                 // Until we are very sure this invarent (ifs that move between passes have then)
    813                 // holds, check it. This allows a check for when to decode the mangling.
    814                 if ( auto ifStmt = catchClause->body.as<ast::IfStmt>() ) {
    815                         assert( ifStmt->then );
    816                 }
    817                 // Encode the catchStmt so the condition can see the declaration.
    818                 if ( catchClause->cond ) {
    819                         ast::CatchClause * clause = mutate( catchClause );
    820                         clause->body = new ast::IfStmt( clause->location, clause->cond, nullptr, clause->body );
    821                         clause->cond = nullptr;
    822                         return clause;
    823                 }
    824                 return catchClause;
    825         }
    826 
    827         const ast::CatchClause * Resolver::postvisit( const ast::CatchClause * catchClause ) {
    828                 // Decode the catchStmt so everything is stored properly.
    829                 const ast::IfStmt * ifStmt = catchClause->body.as<ast::IfStmt>();
    830                 if ( nullptr != ifStmt && nullptr == ifStmt->then ) {
    831                         assert( ifStmt->cond );
    832                         assert( ifStmt->else_ );
    833                         ast::CatchClause * clause = ast::mutate( catchClause );
    834                         clause->cond = ifStmt->cond;
    835                         clause->body = ifStmt->else_;
    836                         // ifStmt should be implicately deleted here.
    837                         return clause;
    838                 }
    839                 return catchClause;
    840         }
    841 
    842         const ast::WaitForStmt * Resolver::previsit( const ast::WaitForStmt * stmt ) {
    843                 visit_children = false;
    844 
    845                 // Resolve all clauses first
    846                 for ( unsigned i = 0; i < stmt->clauses.size(); ++i ) {
    847                         const ast::WaitForClause & clause = *stmt->clauses[i];
    848 
    849                         ast::TypeEnvironment env;
    850                         CandidateFinder funcFinder( context, env );
    851 
    852                         // Find all candidates for a function in canonical form
    853                         funcFinder.find( clause.target, ResolveMode::withAdjustment() );
    854 
    855                         if ( funcFinder.candidates.empty() ) {
    856                                 stringstream ss;
    857                                 ss << "Use of undeclared indentifier '";
    858                                 ss << clause.target.strict_as< ast::NameExpr >()->name;
    859                                 ss << "' in call to waitfor";
    860                                 SemanticError( stmt->location, ss.str() );
    861                         }
    862 
    863                         if ( clause.target_args.empty() ) {
    864                                 SemanticError( stmt->location,
    865                                         "Waitfor clause must have at least one mutex parameter");
    866                         }
    867 
    868                         // Find all alternatives for all arguments in canonical form
    869                         std::vector< CandidateFinder > argFinders =
    870                                 funcFinder.findSubExprs( clause.target_args );
    871 
    872                         // List all combinations of arguments
    873                         std::vector< CandidateList > possibilities;
    874                         combos( argFinders.begin(), argFinders.end(), back_inserter( possibilities ) );
    875 
    876                         // For every possible function:
    877                         // * try matching the arguments to the parameters, not the other way around because
    878                         //   more arguments than parameters
    879                         CandidateList funcCandidates;
    880                         std::vector< CandidateList > argsCandidates;
    881                         SemanticErrorException errors;
    882                         for ( CandidateRef & func : funcFinder.candidates ) {
    883                                 try {
    884                                         auto pointerType = dynamic_cast< const ast::PointerType * >(
    885                                                 func->expr->result->stripReferences() );
    886                                         if ( ! pointerType ) {
    887                                                 SemanticError( stmt->location, func->expr->result.get(),
    888                                                         "candidate not viable: not a pointer type\n" );
    889                                         }
    890 
    891                                         auto funcType = pointerType->base.as< ast::FunctionType >();
    892                                         if ( ! funcType ) {
    893                                                 SemanticError( stmt->location, func->expr->result.get(),
    894                                                         "candidate not viable: not a function type\n" );
    895                                         }
    896 
    897                                         {
    898                                                 auto param    = funcType->params.begin();
    899                                                 auto paramEnd = funcType->params.end();
    900 
    901                                                 if( ! nextMutex( param, paramEnd ) ) {
    902                                                         SemanticError( stmt->location, funcType,
    903                                                                 "candidate function not viable: no mutex parameters\n");
    904                                                 }
    905                                         }
    906 
    907                                         CandidateRef func2{ new Candidate{ *func } };
    908                                         // strip reference from function
    909                                         func2->expr = referenceToRvalueConversion( func->expr, func2->cost );
    910 
    911                                         // Each argument must be matched with a parameter of the current candidate
    912                                         for ( auto & argsList : possibilities ) {
    913                                                 try {
    914                                                         // Declare data structures needed for resolution
    915                                                         ast::OpenVarSet open;
    916                                                         ast::AssertionSet need, have;
    917                                                         ast::TypeEnvironment resultEnv{ func->env };
    918                                                         // Add all type variables as open so that those not used in the
    919                                                         // parameter list are still considered open
    920                                                         resultEnv.add( funcType->forall );
    921 
    922                                                         // load type variables from arguments into one shared space
    923                                                         for ( auto & arg : argsList ) {
    924                                                                 resultEnv.simpleCombine( arg->env );
    925                                                         }
    926 
    927                                                         // Make sure we don't widen any existing bindings
    928                                                         resultEnv.forbidWidening();
    929 
    930                                                         // Find any unbound type variables
    931                                                         resultEnv.extractOpenVars( open );
    932 
    933                                                         auto param = funcType->params.begin();
    934                                                         auto paramEnd = funcType->params.end();
    935 
    936                                                         unsigned n_mutex_param = 0;
    937 
    938                                                         // For every argument of its set, check if it matches one of the
    939                                                         // parameters. The order is important
    940                                                         for ( auto & arg : argsList ) {
    941                                                                 // Ignore non-mutex arguments
    942                                                                 if ( ! nextMutex( param, paramEnd ) ) {
    943                                                                         // We ran out of parameters but still have arguments.
    944                                                                         // This function doesn't match
    945                                                                         SemanticError( stmt->location, funcType,
    946                                                                                 toString("candidate function not viable: too many mutex "
    947                                                                                 "arguments, expected ", n_mutex_param, "\n" ) );
    948                                                                 }
    949 
    950                                                                 ++n_mutex_param;
    951 
    952                                                                 // Check if the argument matches the parameter type in the current scope.
    953                                                                 // ast::ptr< ast::Type > paramType = (*param)->get_type();
    954 
    955                                                                 if (
    956                                                                         ! unify(
    957                                                                                 arg->expr->result, *param, resultEnv, need, have, open )
    958                                                                 ) {
    959                                                                         // Type doesn't match
    960                                                                         stringstream ss;
    961                                                                         ss << "candidate function not viable: no known conversion "
    962                                                                                 "from '";
    963                                                                         ast::print( ss, *param );
    964                                                                         ss << "' to '";
    965                                                                         ast::print( ss, arg->expr->result );
    966                                                                         ss << "' with env '";
    967                                                                         ast::print( ss, resultEnv );
    968                                                                         ss << "'\n";
    969                                                                         SemanticError( stmt->location, funcType, ss.str() );
    970                                                                 }
    971 
    972                                                                 ++param;
    973                                                         }
    974 
    975                                                         // All arguments match!
    976 
    977                                                         // Check if parameters are missing
    978                                                         if ( nextMutex( param, paramEnd ) ) {
    979                                                                 do {
    980                                                                         ++n_mutex_param;
    981                                                                         ++param;
    982                                                                 } while ( nextMutex( param, paramEnd ) );
    983 
    984                                                                 // We ran out of arguments but still have parameters left; this
    985                                                                 // function doesn't match
    986                                                                 SemanticError( stmt->location, funcType,
    987                                                                         toString( "candidate function not viable: too few mutex "
    988                                                                         "arguments, expected ", n_mutex_param, "\n" ) );
    989                                                         }
    990 
    991                                                         // All parameters match!
    992 
    993                                                         // Finish the expressions to tie in proper environments
    994                                                         finishExpr( func2->expr, resultEnv );
    995                                                         for ( CandidateRef & arg : argsList ) {
    996                                                                 finishExpr( arg->expr, resultEnv );
    997                                                         }
    998 
    999                                                         // This is a match, store it and save it for later
    1000                                                         funcCandidates.emplace_back( std::move( func2 ) );
    1001                                                         argsCandidates.emplace_back( std::move( argsList ) );
    1002 
    1003                                                 } catch ( SemanticErrorException & e ) {
    1004                                                         errors.append( e );
    1005                                                 }
    1006                                         }
    1007                                 } catch ( SemanticErrorException & e ) {
    1008                                         errors.append( e );
    1009                                 }
    1010                         }
    1011 
    1012                         // Make sure correct number of arguments
    1013                         if( funcCandidates.empty() ) {
    1014                                 SemanticErrorException top( stmt->location,
    1015                                         "No alternatives for function in call to waitfor" );
    1016                                 top.append( errors );
    1017                                 throw top;
    1018                         }
    1019 
    1020                         if( argsCandidates.empty() ) {
    1021                                 SemanticErrorException top( stmt->location,
    1022                                         "No alternatives for arguments in call to waitfor" );
    1023                                 top.append( errors );
    1024                                 throw top;
    1025                         }
    1026 
    1027                         if( funcCandidates.size() > 1 ) {
    1028                                 SemanticErrorException top( stmt->location,
    1029                                         "Ambiguous function in call to waitfor" );
    1030                                 top.append( errors );
    1031                                 throw top;
    1032                         }
    1033                         if( argsCandidates.size() > 1 ) {
    1034                                 SemanticErrorException top( stmt->location,
    1035                                         "Ambiguous arguments in call to waitfor" );
    1036                                 top.append( errors );
    1037                                 throw top;
    1038                         }
    1039                         // TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.
    1040 
    1041                         // build new clause
    1042                         auto clause2 = new ast::WaitForClause( clause.location );
    1043 
    1044                         clause2->target = funcCandidates.front()->expr;
    1045 
    1046                         clause2->target_args.reserve( clause.target_args.size() );
    1047                         const ast::StructDecl * decl_monitor = symtab.lookupStruct( "monitor$" );
    1048                         for ( auto arg : argsCandidates.front() ) {
    1049                                 const auto & loc = stmt->location;
    1050 
    1051                                 ast::Expr * init = new ast::CastExpr( loc,
    1052                                         new ast::UntypedExpr( loc,
    1053                                                 new ast::NameExpr( loc, "get_monitor" ),
    1054                                                 { arg->expr }
    1055                                         ),
    1056                                         new ast::PointerType(
    1057                                                 new ast::StructInstType(
    1058                                                         decl_monitor
    1059                                                 )
    1060                                         )
    1061                                 );
    1062 
    1063                                 clause2->target_args.emplace_back( findSingleExpression( init, context ) );
    1064                         }
    1065 
    1066                         // Resolve the conditions as if it were an IfStmt, statements normally
    1067                         clause2->when_cond = findSingleExpression( clause.when_cond, context );
    1068                         clause2->stmt = clause.stmt->accept( *visitor );
    1069 
    1070                         // set results into stmt
    1071                         auto n = mutate( stmt );
    1072                         n->clauses[i] = clause2;
    1073                         stmt = n;
    1074                 }
    1075 
    1076                 if ( stmt->timeout_stmt ) {
    1077                         // resolve the timeout as a size_t, the conditions like IfStmt, and stmts normally
    1078                         ast::ptr< ast::Type > target =
    1079                                 new ast::BasicType{ ast::BasicType::LongLongUnsignedInt };
    1080                         auto timeout_time = findSingleExpression( stmt->timeout_time, target, context );
    1081                         auto timeout_cond = findSingleExpression( stmt->timeout_cond, context );
    1082                         auto timeout_stmt = stmt->timeout_stmt->accept( *visitor );
    1083 
    1084                         // set results into stmt
    1085                         auto n = mutate( stmt );
    1086                         n->timeout_time = std::move( timeout_time );
    1087                         n->timeout_cond = std::move( timeout_cond );
    1088                         n->timeout_stmt = std::move( timeout_stmt );
    1089                         stmt = n;
    1090                 }
    1091 
    1092                 if ( stmt->else_stmt ) {
    1093                         // resolve the condition like IfStmt, stmts normally
    1094                         auto else_cond = findSingleExpression( stmt->else_cond, context );
    1095                         auto else_stmt = stmt->else_stmt->accept( *visitor );
    1096 
    1097                         // set results into stmt
    1098                         auto n = mutate( stmt );
    1099                         n->else_cond = std::move( else_cond );
    1100                         n->else_stmt = std::move( else_stmt );
    1101                         stmt = n;
    1102                 }
    1103 
    1104                 return stmt;
    1105         }
    1106 
    1107         const ast::WithStmt * Resolver::previsit( const ast::WithStmt * withStmt ) {
    1108                 auto mutStmt = mutate(withStmt);
    1109                 resolveWithExprs(mutStmt->exprs, stmtsToAddBefore);
    1110                 return mutStmt;
    1111         }
    1112 
    1113         void Resolver::resolveWithExprs(std::vector<ast::ptr<ast::Expr>> & exprs, std::list<ast::ptr<ast::Stmt>> & stmtsToAdd) {
    1114                 for (auto & expr : exprs) {
    1115                         // only struct- and union-typed expressions are viable candidates
    1116                         expr = findKindExpression( expr, context, structOrUnion, "with expression" );
    1117 
    1118                         // if with expression might be impure, create a temporary so that it is evaluated once
    1119                         if ( Tuples::maybeImpure( expr ) ) {
    1120                                 static UniqueName tmpNamer( "_with_tmp_" );
    1121                                 const CodeLocation loc = expr->location;
    1122                                 auto tmp = new ast::ObjectDecl(loc, tmpNamer.newName(), expr->result, new ast::SingleInit(loc, expr ) );
    1123                                 expr = new ast::VariableExpr( loc, tmp );
    1124                                 stmtsToAdd.push_back( new ast::DeclStmt(loc, tmp ) );
    1125                                 if ( InitTweak::isConstructable( tmp->type ) ) {
    1126                                         // generate ctor/dtor and resolve them
    1127                                         tmp->init = InitTweak::genCtorInit( loc, tmp );
    1128                                 }
    1129                                 // since tmp is freshly created, this should modify tmp in-place
    1130                                 tmp->accept( *visitor );
    1131                         }
    1132                         else if (expr->env && expr->env->empty()) {
    1133                                 expr = ast::mutate_field(expr.get(), &ast::Expr::env, nullptr);
    1134                         }
    1135                 }
    1136         }
    1137 
    1138 
    1139         const ast::SingleInit * Resolver::previsit( const ast::SingleInit * singleInit ) {
    1140                 visit_children = false;
    1141                 // resolve initialization using the possibilities as determined by the `currentObject`
    1142                 // cursor.
    1143                 ast::ptr< ast::Expr > untyped = new ast::UntypedInitExpr{
    1144                         singleInit->location, singleInit->value, currentObject.getOptions() };
    1145                 ast::ptr<ast::Expr> newExpr = findSingleExpression( untyped, context );
    1146                 const ast::InitExpr * initExpr = newExpr.strict_as< ast::InitExpr >();
    1147 
    1148                 // move cursor to the object that is actually initialized
    1149                 currentObject.setNext( initExpr->designation );
    1150 
    1151                 // discard InitExpr wrapper and retain relevant pieces.
    1152                 // `initExpr` may have inferred params in the case where the expression specialized a
    1153                 // function pointer, and newExpr may already have inferParams of its own, so a simple
    1154                 // swap is not sufficient
    1155                 ast::Expr::InferUnion inferred = initExpr->inferred;
    1156                 swap_and_save_env( newExpr, initExpr->expr );
    1157                 newExpr.get_and_mutate()->inferred.splice( std::move(inferred) );
    1158 
    1159                 // get the actual object's type (may not exactly match what comes back from the resolver
    1160                 // due to conversions)
    1161                 const ast::Type * initContext = currentObject.getCurrentType();
    1162 
    1163                 removeExtraneousCast( newExpr );
    1164 
    1165                 // check if actual object's type is char[]
    1166                 if ( auto at = dynamic_cast< const ast::ArrayType * >( initContext ) ) {
    1167                         if ( isCharType( at->base ) ) {
    1168                                 // check if the resolved type is char*
    1169                                 if ( auto pt = newExpr->result.as< ast::PointerType >() ) {
    1170                                         if ( isCharType( pt->base ) ) {
    1171                                                 // strip cast if we're initializing a char[] with a char*
    1172                                                 // e.g. char x[] = "hello"
    1173                                                 if ( auto ce = newExpr.as< ast::CastExpr >() ) {
    1174                                                         swap_and_save_env( newExpr, ce->arg );
    1175                                                 }
    1176                                         }
    1177                                 }
    1178                         }
    1179                 }
    1180 
    1181                 // move cursor to next object in preparation for next initializer
    1182                 currentObject.increment();
    1183 
    1184                 // set initializer expression to resolved expression
    1185                 return ast::mutate_field( singleInit, &ast::SingleInit::value, std::move(newExpr) );
    1186         }
    1187 
    1188         const ast::ListInit * Resolver::previsit( const ast::ListInit * listInit ) {
    1189                 // move cursor into brace-enclosed initializer-list
    1190                 currentObject.enterListInit( listInit->location );
    1191 
    1192                 assert( listInit->designations.size() == listInit->initializers.size() );
    1193                 for ( unsigned i = 0; i < listInit->designations.size(); ++i ) {
    1194                         // iterate designations and initializers in pairs, moving the cursor to the current
    1195                         // designated object and resolving the initializer against that object
    1196                         listInit = ast::mutate_field_index(
    1197                                 listInit, &ast::ListInit::designations, i,
    1198                                 currentObject.findNext( listInit->designations[i] ) );
    1199                         listInit = ast::mutate_field_index(
    1200                                 listInit, &ast::ListInit::initializers, i,
    1201                                 listInit->initializers[i]->accept( *visitor ) );
    1202                 }
    1203 
    1204                 // move cursor out of brace-enclosed initializer-list
    1205                 currentObject.exitListInit();
    1206 
    1207                 visit_children = false;
    1208                 return listInit;
    1209         }
    1210 
    1211         const ast::ConstructorInit * Resolver::previsit( const ast::ConstructorInit * ctorInit ) {
    1212                 visitor->maybe_accept( ctorInit, &ast::ConstructorInit::ctor );
    1213                 visitor->maybe_accept( ctorInit, &ast::ConstructorInit::dtor );
    1214 
    1215                 // found a constructor - can get rid of C-style initializer
    1216                 // xxx - Rob suggests this field is dead code
    1217                 ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::init, nullptr );
    1218 
    1219                 // intrinsic single-parameter constructors and destructors do nothing. Since this was
    1220                 // implicitly generated, there's no way for it to have side effects, so get rid of it to
    1221                 // clean up generated code
    1222                 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->ctor ) ) {
    1223                         ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::ctor, nullptr );
    1224                 }
    1225                 if ( InitTweak::isIntrinsicSingleArgCallStmt( ctorInit->dtor ) ) {
    1226                         ctorInit = ast::mutate_field( ctorInit, &ast::ConstructorInit::dtor, nullptr );
    1227                 }
    1228 
    1229                 return ctorInit;
    1230         }
    1231 
    1232         // suppress error on autogen functions and mark invalid autogen as deleted.
    1233         bool Resolver::on_error(ast::ptr<ast::Decl> & decl) {
    1234                 if (auto functionDecl = decl.as<ast::FunctionDecl>()) {
    1235                         // xxx - can intrinsic gen ever fail?
    1236                         if (functionDecl->linkage == ast::Linkage::AutoGen) {
    1237                                 auto mutDecl = mutate(functionDecl);
    1238                                 mutDecl->isDeleted = true;
    1239                                 mutDecl->stmts = nullptr;
    1240                                 decl = mutDecl;
    1241                                 return false;
    1242                         }
    1243                 }
    1244                 return true;
    1245         }
     1239        }
     1240        return true;
     1241}
    12461242
    12471243} // namespace ResolvExpr
Note: See TracChangeset for help on using the changeset viewer.