Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/CandidateFinder.cpp

    rc8e4d2f8 r898ae07  
    2727#include "Cost.h"
    2828#include "ExplodedArg.hpp"
     29#include "RenameVars.h"           // for renameTyVars
    2930#include "Resolver.h"
    3031#include "ResolveTypeof.h"
     
    557558
    558559        /// Generate a cast expression from `arg` to `toType`
    559         const ast::Expr * restructureCast( const ast::Expr * arg, const ast::Type * toType, bool isGenerated ) {
    560                 #warning unimplemented
    561                 (void)arg; (void)toType; (void)isGenerated;
    562                 assert(false);
    563                 return nullptr;
     560        const ast::Expr * restructureCast(
     561                ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated
     562        ) {
     563                if (
     564                        arg->result->size() > 1
     565                        && ! toType->isVoid()
     566                        && ! dynamic_cast< const ast::ReferenceType * >( toType )
     567                ) {
     568                        // Argument is a tuple and the target type is neither void nor a reference. Cast each
     569                        // member of the tuple to its corresponding target type, producing the tuple of those
     570                        // cast expressions. If there are more components of the tuple than components in the
     571                        // target type, then excess components do not come out in the result expression (but
     572                        // UniqueExpr ensures that the side effects will still be produced)
     573                        if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
     574                                // expressions which may contain side effects require a single unique instance of
     575                                // the expression
     576                                arg = new ast::UniqueExpr{ arg->location, arg };
     577                        }
     578                        std::vector< ast::ptr< ast::Expr > > components;
     579                        for ( unsigned i = 0; i < toType->size(); ++i ) {
     580                                // cast each component
     581                                ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i };
     582                                components.emplace_back(
     583                                        restructureCast( idx, toType->getComponent( i ), isGenerated ) );
     584                        }
     585                        return new ast::TupleExpr{ arg->location, move( components ) };
     586                } else {
     587                        // handle normally
     588                        return new ast::CastExpr{ arg->location, arg, toType, isGenerated };
     589                }
     590        }
     591
     592        /// Gets the name from an untyped member expression (must be NameExpr)
     593        const std::string & getMemberName( const ast::UntypedMemberExpr * memberExpr ) {
     594                if ( memberExpr->member.as< ast::ConstantExpr >() ) {
     595                        SemanticError( memberExpr, "Indexed access to struct fields unsupported: " );
     596                }
     597
     598                return memberExpr->member.strict_as< ast::NameExpr >()->name;
    564599        }
    565600
     
    764799
    765800                        if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) {
    766                                 addAggMembers( structInst, aggrExpr, cand, Cost::safe, "" );
     801                                addAggMembers( structInst, aggrExpr, *cand, Cost::safe, "" );
    767802                        } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) {
    768                                 addAggMembers( unionInst, aggrExpr, cand, Cost::safe, "" );
     803                                addAggMembers( unionInst, aggrExpr, *cand, Cost::safe, "" );
    769804                        }
    770805                }
     
    773808                void addAggMembers(
    774809                        const ast::ReferenceToType * aggrInst, const ast::Expr * expr,
    775                         const CandidateRef & cand, const Cost & addedCost, const std::string & name
     810                        const Candidate & cand, const Cost & addedCost, const std::string & name
    776811                ) {
    777812                        for ( const ast::Decl * decl : aggrInst->lookup( name ) ) {
    778813                                auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl );
    779814                                CandidateRef newCand = std::make_shared<Candidate>(
    780                                         *cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost );
     815                                        cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost );
    781816                                // add anonymous member interpretations whenever an aggregate value type is seen
    782817                                // as a member expression
    783818                                addAnonConversions( newCand );
    784819                                candidates.emplace_back( move( newCand ) );
     820                        }
     821                }
     822
     823                /// Adds tuple member interpretations
     824                void addTupleMembers(
     825                        const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,
     826                        const Cost & addedCost, const ast::Expr * member
     827                ) {
     828                        if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) {
     829                                // get the value of the constant expression as an int, must be between 0 and the
     830                                // length of the tuple to have meaning
     831                                long long val = constantExpr->intValue();
     832                                if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {
     833                                        addCandidate(
     834                                                cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val },
     835                                                addedCost );
     836                                }
    785837                        }
    786838                }
     
    10001052                        }
    10011053
    1002                         // castExpr->result should be replaced with toType
    1003                         // candidates => matches
    1004 
    1005                         #warning unimplemented
    1006                         (void)castExpr;
    1007                         assert(false);
     1054                        // select first on argument cost, then conversion cost
     1055                        CandidateList minArgCost = findMinCost( matches );
     1056                        promoteCvtCost( minArgCost );
     1057                        candidates = findMinCost( minArgCost );
    10081058                }
    10091059
     
    10211071
    10221072                void postvisit( const ast::UntypedMemberExpr * memberExpr ) {
    1023                         #warning unimplemented
    1024                         (void)memberExpr;
    1025                         assert(false);
     1073                        CandidateFinder aggFinder{ symtab, tenv };
     1074                        aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() );
     1075                        for ( CandidateRef & agg : aggFinder.candidates ) {
     1076                                // it's okay for the aggregate expression to have reference type -- cast it to the
     1077                                // base type to treat the aggregate as the referenced value
     1078                                Cost addedCost = Cost::zero;
     1079                                agg->expr = referenceToRvalueConversion( agg->expr, addedCost );
     1080
     1081                                // find member of the given type
     1082                                if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) {
     1083                                        addAggMembers(
     1084                                                structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
     1085                                } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) {
     1086                                        addAggMembers(
     1087                                                unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
     1088                                } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) {
     1089                                        addTupleMembers( tupleType, agg->expr, *agg, addedCost, memberExpr->member );
     1090                                }
     1091                        }
    10261092                }
    10271093
     
    10301096                }
    10311097
    1032                 void postvisit( const ast::NameExpr * variableExpr ) {
    1033                         #warning unimplemented
    1034                         (void)variableExpr;
    1035                         assert(false);
     1098                void postvisit( const ast::NameExpr * nameExpr ) {
     1099                        std::vector< ast::SymbolTable::IdData > declList = symtab.lookupId( nameExpr->name );
     1100                        PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
     1101                        for ( auto & data : declList ) {
     1102                                Cost cost = Cost::zero;
     1103                                ast::Expr * newExpr = data.combine( nameExpr->location, cost );
     1104
     1105                                CandidateRef newCand = std::make_shared<Candidate>(
     1106                                        newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
     1107                                        cost );
     1108                                PRINT(
     1109                                        std::cerr << "decl is ";
     1110                                        ast::print( std::cerr, data.id );
     1111                                        std::cerr << std::endl;
     1112                                        std::cerr << "newExpr is ";
     1113                                        ast::print( std::cerr, newExpr );
     1114                                        std::cerr << std::endl;
     1115                                )
     1116                                newCand->expr = ast::mutate_field(
     1117                                        newCand->expr.get(), &ast::Expr::result,
     1118                                        renameTyVars( newCand->expr->result ) );
     1119                                // add anonymous member interpretations whenever an aggregate value type is seen
     1120                                // as a name expression
     1121                                addAnonConversions( newCand );
     1122                                candidates.emplace_back( move( newCand ) );
     1123                        }
    10361124                }
    10371125
     
    10481136
    10491137                void postvisit( const ast::SizeofExpr * sizeofExpr ) {
    1050                         #warning unimplemented
    1051                         (void)sizeofExpr;
    1052                         assert(false);
     1138                        if ( sizeofExpr->type ) {
     1139                                addCandidate(
     1140                                        new ast::SizeofExpr{
     1141                                                sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) },
     1142                                        tenv );
     1143                        } else {
     1144                                // find all candidates for the argument to sizeof
     1145                                CandidateFinder finder{ symtab, tenv };
     1146                                finder.find( sizeofExpr->expr );
     1147                                // find the lowest-cost candidate, otherwise ambiguous
     1148                                CandidateList winners = findMinCost( finder.candidates );
     1149                                if ( winners.size() != 1 ) {
     1150                                        SemanticError(
     1151                                                sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " );
     1152                                }
     1153                                // return the lowest-cost candidate
     1154                                CandidateRef & choice = winners.front();
     1155                                choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
     1156                                choice->cost = Cost::zero;
     1157                                addCandidate( *choice, new ast::SizeofExpr{ sizeofExpr->location, choice->expr } );
     1158                        }
    10531159                }
    10541160
    10551161                void postvisit( const ast::AlignofExpr * alignofExpr ) {
    1056                         #warning unimplemented
    1057                         (void)alignofExpr;
    1058                         assert(false);
     1162                        if ( alignofExpr->type ) {
     1163                                addCandidate(
     1164                                        new ast::AlignofExpr{
     1165                                                alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) },
     1166                                        tenv );
     1167                        } else {
     1168                                // find all candidates for the argument to alignof
     1169                                CandidateFinder finder{ symtab, tenv };
     1170                                finder.find( alignofExpr->expr );
     1171                                // find the lowest-cost candidate, otherwise ambiguous
     1172                                CandidateList winners = findMinCost( finder.candidates );
     1173                                if ( winners.size() != 1 ) {
     1174                                        SemanticError(
     1175                                                alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " );
     1176                                }
     1177                                // return the lowest-cost candidate
     1178                                CandidateRef & choice = winners.front();
     1179                                choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
     1180                                choice->cost = Cost::zero;
     1181                                addCandidate(
     1182                                        *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } );
     1183                        }
    10591184                }
    10601185
    10611186                void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) {
    1062                         #warning unimplemented
    1063                         (void)offsetofExpr;
    1064                         assert(false);
     1187                        const ast::ReferenceToType * aggInst;
     1188                        if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ;
     1189                        else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ;
     1190                        else return;
     1191
     1192                        for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) {
     1193                                auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member );
     1194                                addCandidate(
     1195                                        new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv );
     1196                        }
    10651197                }
    10661198
     
    11391271                                                                common )
    11401272                                                ) {
    1141                                                         #warning unimplemented
    1142                                                         assert(false);
     1273                                                        // generate typed expression
     1274                                                        ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{
     1275                                                                conditionalExpr->location, r1->expr, r2->expr, r3->expr };
     1276                                                        newExpr->result = common ? common : r2->expr->result;
     1277                                                        // convert both options to result type
     1278                                                        Cost cost = r1->cost + r2->cost + r3->cost;
     1279                                                        newExpr->arg2 = computeExpressionConversionCost(
     1280                                                                newExpr->arg2, newExpr->result, symtab, env, cost );
     1281                                                        newExpr->arg3 = computeExpressionConversionCost(
     1282                                                                newExpr->arg3, newExpr->result, symtab, env, cost );
     1283                                                        // output candidate
     1284                                                        CandidateRef newCand = std::make_shared<Candidate>(
     1285                                                                newExpr, move( env ), move( open ), move( need ), cost );
     1286                                                        inferParameters( newCand, candidates );
    11431287                                                }
    11441288                                        }
     
    11981342                                                        common )
    11991343                                        ) {
     1344                                                // generate new expression
    12001345                                                ast::RangeExpr * newExpr =
    12011346                                                        new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };
    12021347                                                newExpr->result = common ? common : r1->expr->result;
    1203                                                
    1204                                                 #warning unimplemented
    1205                                                 assert(false);
     1348                                                // add candidate
     1349                                                CandidateRef newCand = std::make_shared<Candidate>(
     1350                                                        newExpr, move( env ), move( open ), move( need ),
     1351                                                        r1->cost + r2->cost );
     1352                                                inferParameters( newCand, candidates );
    12061353                                        }
    12071354                                }
Note: See TracChangeset for help on using the changeset viewer.