Changeset c71b256


Ignore:
Timestamp:
Feb 16, 2018, 4:14:29 PM (6 years ago)
Author:
Rob Schluntz <rschlunt@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
Children:
7c782af
Parents:
4a161be
Message:

Add resolver error when a deleted identifier is in the final lowest cost interpretation, refactor top-level resolver functions

Location:
src/ResolvExpr
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/AlternativeFinder.cc

    r4a161be rc71b256  
    9595                void postvisit( StmtExpr * stmtExpr );
    9696                void postvisit( UntypedInitExpr * initExpr );
     97                void postvisit( InitExpr * initExpr );
     98                void postvisit( DeletedExpr * delExpr );
    9799
    98100                /// Adds alternatives for anonymous members
     
    120122                Type *& targetType;
    121123        };
    122 
    123         Expression *resolveInVoidContext( Expression *expr, const SymTab::Indexer &indexer, TypeEnvironment &env ) {
    124                 CastExpr *castToVoid = new CastExpr( expr );
    125 
    126                 AlternativeFinder finder( indexer, env );
    127                 finder.findWithAdjustment( castToVoid );
    128 
    129                 // it's a property of the language that a cast expression has either 1 or 0 interpretations; if it has 0
    130                 // interpretations, an exception has already been thrown.
    131                 assert( finder.get_alternatives().size() == 1 );
    132                 CastExpr *newExpr = dynamic_cast< CastExpr* >( finder.get_alternatives().front().expr );
    133                 assert( newExpr );
    134                 env = finder.get_alternatives().front().env;
    135                 return newExpr->get_arg()->clone();
    136         }
    137124
    138125        Cost sumCost( const AltList &in ) {
     
    17511738                findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );
    17521739        }
     1740
     1741        void AlternativeFinder::Finder::postvisit( InitExpr * ) {
     1742                assertf( false, "AlternativeFinder should never see a resolved InitExpr." );
     1743        }
     1744
     1745        void AlternativeFinder::Finder::postvisit( DeletedExpr * ) {
     1746                assertf( false, "AlternativeFinder should never see a DeletedExpr." );
     1747        }
    17531748} // namespace ResolvExpr
    17541749
  • src/ResolvExpr/Resolver.cc

    r4a161be rc71b256  
    105105        }
    106106
    107         // used in resolveTypeof
    108         Expression *resolveInVoidContext( Expression *expr, const SymTab::Indexer &indexer ) {
    109                 TypeEnvironment env;
    110                 return resolveInVoidContext( expr, indexer, env );
     107        namespace {
     108                struct DeleteFinder : public WithShortCircuiting        {
     109                        DeletedExpr * delExpr = nullptr;
     110                        void previsit( DeletedExpr * expr ) {
     111                                if ( delExpr ) visit_children = false;
     112                                else delExpr = expr;
     113                        }
     114
     115                        void previsit( Expression * ) {
     116                                if ( delExpr ) visit_children = false;
     117                        }
     118                };
     119        }
     120
     121        DeletedExpr * findDeletedExpr( Expression * expr ) {
     122                PassVisitor<DeleteFinder> finder;
     123                expr->accept( finder );
     124                return finder.pass.delExpr;
    111125        }
    112126
     
    130144        } // namespace
    131145
     146        namespace {
     147                void findUnfinishedKindExpression(Expression * untyped, Alternative & alt, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, bool adjust = false, bool prune = true, bool failFast = true) {
     148                        assertf( untyped, "expected a non-null expression." );
     149                        TypeEnvironment env;
     150                        AlternativeFinder finder( indexer, env );
     151                        finder.find( untyped, adjust, prune, failFast );
     152
     153                        #if 0
     154                        if ( finder.get_alternatives().size() != 1 ) {
     155                                std::cerr << "untyped expr is ";
     156                                untyped->print( std::cerr );
     157                                std::cerr << std::endl << "alternatives are:";
     158                                for ( const Alternative & alt : finder.get_alternatives() ) {
     159                                        alt.print( std::cerr );
     160                                } // for
     161                        } // if
     162                        #endif
     163
     164                        AltList candidates;
     165                        for ( Alternative & alt : finder.get_alternatives() ) {
     166                                if ( pred( alt ) ) {
     167                                        candidates.push_back( std::move( alt ) );
     168                                }
     169                        }
     170
     171                        // xxx - if > 1 alternative with same cost, ignore deleted and pick from remaining
     172                        // choose the lowest cost expression among the candidates
     173                        AltList winners;
     174                        findMinCost( candidates.begin(), candidates.end(), back_inserter( winners ) );
     175                        if ( winners.size() == 0 ) {
     176                                throw SemanticError( toString( "No reasonable alternatives for ", kindStr, (kindStr != "" ? " " : ""), "expression: "), untyped );
     177                        } else if ( winners.size() != 1 ) {
     178                                std::ostringstream stream;
     179                                stream << "Cannot choose between " << winners.size() << " alternatives for " << kindStr << (kindStr != "" ? " " : "") << "expression\n";
     180                                untyped->print( stream );
     181                                stream << "Alternatives are:\n";
     182                                printAlts( winners, stream, 1 );
     183                                throw SemanticError( stream.str() );
     184                        }
     185
     186                        // there is one unambiguous interpretation - move the expression into the with statement
     187                        Alternative & choice = winners.front();
     188                        if ( findDeletedExpr( choice.expr ) ) {
     189                                throw SemanticError( "Unique best alternative includes deleted identifier in ", choice.expr );
     190                        }
     191                        alt = std::move( choice );
     192                }
     193
     194                /// resolve `untyped` to the expression whose alternative satisfies `pred` with the lowest cost; kindStr is used for providing better error messages
     195                void findKindExpression(Expression *& untyped, const SymTab::Indexer & indexer, const std::string & kindStr, std::function<bool(const Alternative &)> pred, bool adjust = false, bool prune = true, bool failFast = true) {
     196                        if ( ! untyped ) return;
     197                        Alternative choice;
     198                        findUnfinishedKindExpression( untyped, choice, indexer, kindStr, pred, adjust, prune, failFast );
     199                        finishExpr( choice.expr, choice.env, untyped->env );
     200                        delete untyped;
     201                        untyped = choice.expr;
     202                        choice.expr = nullptr;
     203                }
     204
     205                bool standardAlternativeFilter( const Alternative & ) {
     206                        // currently don't need to filter, under normal circumstances.
     207                        // in the future, this may be useful for removing deleted expressions
     208                        return true;
     209                }
     210        } // namespace
     211
     212        // used in resolveTypeof
     213        Expression * resolveInVoidContext( Expression *expr, const SymTab::Indexer &indexer ) {
     214                TypeEnvironment env;
     215                return resolveInVoidContext( expr, indexer, env );
     216        }
     217
     218        Expression * resolveInVoidContext( Expression *expr, const SymTab::Indexer &indexer, TypeEnvironment &env ) {
     219                // it's a property of the language that a cast expression has either 1 or 0 interpretations; if it has 0
     220                // interpretations, an exception has already been thrown.
     221                assertf( expr, "expected a non-null expression." );
     222
     223                static CastExpr untyped( nullptr ); // cast to void
     224
     225                // set up and resolve expression cast to void
     226                untyped.arg = expr;
     227                Alternative choice;
     228                findUnfinishedKindExpression( &untyped, choice, indexer, "", standardAlternativeFilter, true );
     229                CastExpr * castExpr = strict_dynamic_cast< CastExpr * >( choice.expr );
     230                env = std::move( choice.env );
     231
     232                // clean up resolved expression
     233                Expression * ret = castExpr->arg;
     234                castExpr->arg = nullptr;
     235
     236                // unlink the arg so that it isn't deleted twice at the end of the program
     237                untyped.arg = nullptr;
     238                return ret;
     239        }
     240
    132241        void findVoidExpression( Expression *& untyped, const SymTab::Indexer &indexer ) {
    133242                resetTyVarRenaming();
    134243                TypeEnvironment env;
    135                 Expression *newExpr = resolveInVoidContext( untyped, indexer, env );
     244                Expression * newExpr = resolveInVoidContext( untyped, indexer, env );
    136245                finishExpr( newExpr, env, untyped->env );
    137246                delete untyped;
     
    140249
    141250        void findSingleExpression( Expression *&untyped, const SymTab::Indexer &indexer ) {
    142                 if ( ! untyped ) return;
    143                 TypeEnvironment env;
    144                 AlternativeFinder finder( indexer, env );
    145                 finder.find( untyped );
    146                 #if 0
    147                 if ( finder.get_alternatives().size() != 1 ) {
    148                         std::cerr << "untyped expr is ";
    149                         untyped->print( std::cerr );
    150                         std::cerr << std::endl << "alternatives are:";
    151                         for ( const Alternative & alt : finder.get_alternatives() ) {
    152                                 alt.print( std::cerr );
    153                         } // for
    154                 } // if
    155                 #endif
    156                 assertf( finder.get_alternatives().size() == 1, "findSingleExpression: must have exactly one alternative at the end: (%zd) %s", finder.get_alternatives().size(), toString( untyped ).c_str() );
    157                 Alternative &choice = finder.get_alternatives().front();
    158                 Expression *newExpr = choice.expr->clone();
    159                 finishExpr( newExpr, choice.env, untyped->env );
    160                 delete untyped;
    161                 untyped = newExpr;
     251                findKindExpression( untyped, indexer, "", standardAlternativeFilter );
    162252        }
    163253
     
    170260
    171261        namespace {
    172                 /// resolve `untyped` to the expression whose type satisfies `pred` with the lowest cost; kindStr is used for providing better error messages
    173                 template<typename Pred>
    174                 void findKindExpression(Expression *& untyped, const SymTab::Indexer & indexer, const std::string & kindStr, Pred pred) {
    175                         TypeEnvironment env;
    176                         AlternativeFinder finder( indexer, env );
    177                         finder.findWithAdjustment( untyped );
    178 
    179                         AltList candidates;
    180                         for ( Alternative & alt : finder.get_alternatives() ) {
    181                                 if ( pred( alt.expr->result ) ) {
    182                                         candidates.push_back( std::move( alt ) );
    183                                 }
    184                         }
    185 
    186                         // choose the lowest cost expression among the candidates
    187                         AltList winners;
    188                         findMinCost( candidates.begin(), candidates.end(), back_inserter( winners ) );
    189                         if ( winners.size() == 0 ) {
    190                                 throw SemanticError( "No reasonable alternatives for " + kindStr + " expression: ", untyped );
    191                         } else if ( winners.size() != 1 ) {
    192                                 std::ostringstream stream;
    193                                 stream << "Cannot choose between " << winners.size() << " alternatives for " + kindStr +  " expression\n";
    194                                 untyped->print( stream );
    195                                 stream << "Alternatives are:\n";
    196                                 printAlts( winners, stream, 1 );
    197                                 throw SemanticError( stream.str() );
    198                         }
    199 
    200                         // there is one unambiguous interpretation - move the expression into the with statement
    201                         Alternative & alt = winners.front();
    202                         finishExpr( alt.expr, alt.env, untyped->env );
    203                         delete untyped;
    204                         untyped = alt.expr;
    205                         alt.expr = nullptr;
    206                 }
    207 
    208                 bool isIntegralType( Type *type ) {
     262                bool isIntegralType( const Alternative & alt ) {
     263                        Type * type = alt.expr->result;
    209264                        if ( dynamic_cast< EnumInstType * >( type ) ) {
    210265                                return true;
     
    559614                        if( func_candidates.size() > 1 ) { SemanticError top( "Ambiguous function in call to waitfor"            ); top.append( errors ); throw top; }
    560615                        if( args_candidates.size() > 1 ) { SemanticError top( "Ambiguous arguments in call to waitfor"           ); top.append( errors ); throw top; }
    561 
     616                        // TODO: need to use findDeletedExpr to ensure no deleted identifiers are used.
    562617
    563618                        // Swap the results from the alternative with the unresolved values.
     
    592647        }
    593648
    594         bool isStructOrUnion( Type * t ) {
    595                 t = t->stripReferences();
     649        bool isStructOrUnion( const Alternative & alt ) {
     650                Type * t = alt.expr->result->stripReferences();
    596651                return dynamic_cast< StructInstType * >( t ) || dynamic_cast< UnionInstType * >( t );
    597652        }
Note: See TracChangeset for help on using the changeset viewer.