Ignore:
Timestamp:
Jun 11, 2019, 5:52:50 PM (5 years ago)
Author:
Aaron Moss <a3moss@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
6625727
Parents:
4b7cce6
Message:

Port CandidateFinder::postvisit for UntypedExpr?, stub dependencies

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ResolvExpr/CandidateFinder.cpp

    r4b7cce6 r432ce7a  
    1616#include "CandidateFinder.hpp"
    1717
     18#include <deque>
    1819#include <iterator>               // for back_inserter
    1920#include <sstream>
    2021#include <string>
    2122#include <unordered_map>
     23#include <vector>
    2224
    2325#include "Candidate.hpp"
    2426#include "CompilationState.h"
    2527#include "Cost.h"
     28#include "ExplodedArg.hpp"
    2629#include "Resolver.h"
    2730#include "SatisfyAssertions.hpp"
     
    3336#include "AST/Print.hpp"
    3437#include "AST/SymbolTable.hpp"
     38#include "AST/Type.hpp"
    3539#include "SymTab/Mangler.h"
     40#include "Tuples/Tuples.h"        // for handleTupleAssignment
    3641
    3742#define PRINT( text ) if ( resolvep ) { text }
     
    4045
    4146namespace {
     47
     48        /// First index is which argument, second is which alternative, third is which exploded element
     49        using ExplodedArgs_new = std::deque< std::vector< ExplodedArg > >;
     50
     51        /// Returns a list of alternatives with the minimum cost in the given list
     52        CandidateList findMinCost( const CandidateList & candidates ) {
     53                CandidateList out;
     54                Cost minCost = Cost::infinity;
     55                for ( const CandidateRef & r : candidates ) {
     56                        if ( r->cost < minCost ) {
     57                                minCost = r->cost;
     58                                out.clear();
     59                                out.emplace_back( r );
     60                        } else if ( r->cost == minCost ) {
     61                                out.emplace_back( r );
     62                        }
     63                }
     64                return out;
     65        }
     66
     67        /// Computes conversion cost for a given candidate
     68        Cost computeApplicationConversionCost(
     69                const CandidateRef & cand, const ast::SymbolTable & symtab
     70        ) {
     71                #warning unimplemented
     72                (void)cand; (void)symtab;
     73                assert(false);
     74                return Cost::infinity;
     75        }
    4276
    4377        /// Actually visits expressions to find their candidate interpretations
     
    6599                }
    66100
     101                /// Builds a list of candidates for a function, storing them in out
     102                void makeFunctionCandidates(
     103                        const CandidateRef & func, const ast::FunctionType * funcType,
     104                        const ExplodedArgs_new & args, CandidateList & out
     105                ) {
     106                        #warning unimplemented
     107                        (void)func; (void)funcType; (void)args; (void)out;
     108                        assert(false);
     109                }
     110
     111                /// Adds implicit struct-conversions to the alternative list
     112                void addAnonConversions( const CandidateRef & cand ) {
     113                        #warning unimplemented
     114                        (void)cand;
     115                        assert(false);
     116                }
     117
    67118                void postvisit( const ast::UntypedExpr * untypedExpr ) {
    68                         #warning unimplemented
    69                         (void)untypedExpr;
    70                         assert(false);
     119                        CandidateFinder funcFinder{ symtab, tenv };
     120                        funcFinder.find( untypedExpr->func, ResolvMode::withAdjustment() );
     121                        // short-circuit if no candidates
     122                        if ( funcFinder.candidates.empty() ) return;
     123
     124                        std::vector< CandidateFinder > argCandidates =
     125                                selfFinder.findSubExprs( untypedExpr->args );
     126                       
     127                        // take care of possible tuple assignments
     128                        // if not tuple assignment, handled as normal function call
     129                        Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates );
     130
     131                        // find function operators
     132                        ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" };
     133                        CandidateFinder opFinder{ symtab, tenv };
     134                        // okay if there aren't any function operations
     135                        opFinder.find( opExpr, ResolvMode::withoutFailFast() );
     136                        PRINT(
     137                                std::cerr << "known function ops:" << std::endl;
     138                                print( std::cerr, opFinder.candidates, 1 );
     139                        )
     140
     141                        // pre-explode arguments
     142                        ExplodedArgs_new argExpansions;
     143                        for ( const CandidateFinder & args : argCandidates ) {
     144                                argExpansions.emplace_back();
     145                                auto & argE = argExpansions.back();
     146                                for ( const CandidateRef & arg : args ) { argE.emplace_back( *arg, symtab ); }
     147                        }
     148
     149                        // Find function matches
     150                        CandidateList found;
     151                        SemanticErrorException errors;
     152                        for ( CandidateRef & func : funcFinder ) {
     153                                try {
     154                                        PRINT(
     155                                                std::cerr << "working on alternative:" << std::endl;
     156                                                print( std::cerr, *func, 2 );
     157                                        )
     158
     159                                        // check if the type is a pointer to function
     160                                        const ast::Type * funcResult = func->expr->result->stripReferences();
     161                                        if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) {
     162                                                if ( auto function = pointer->base.as< ast::FunctionType >() ) {
     163                                                        CandidateRef newFunc{ new Candidate{ *func } };
     164                                                        newFunc->expr =
     165                                                                referenceToRvalueConversion( newFunc->expr, newFunc->cost );
     166                                                        makeFunctionCandidates( newFunc, function, argExpansions, found );
     167                                                }
     168                                        } else if (
     169                                                auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )
     170                                        ) {
     171                                                if ( const ast::EqvClass * clz = func->env.lookup( inst->name ) ) {
     172                                                        if ( auto function = clz->bound.as< ast::FunctionType >() ) {
     173                                                                CandidateRef newFunc{ new Candidate{ *func } };
     174                                                                newFunc->expr =
     175                                                                        referenceToRvalueConversion( newFunc->expr, newFunc->cost );
     176                                                                makeFunctionCandidates( newFunc, function, argExpansions, found );
     177                                                        }
     178                                                }
     179                                        }
     180                                } catch ( SemanticErrorException & e ) { errors.append( e ); }
     181                        }
     182
     183                        // Find matches on function operators `?()`
     184                        if ( ! opFinder.candidates.empty() ) {
     185                                // add exploded function alternatives to front of argument list
     186                                std::vector< ExplodedArg > funcE;
     187                                funcE.reserve( funcFinder.candidates.size() );
     188                                for ( const CandidateRef & func : funcFinder ) {
     189                                        funcE.emplace_back( *func, symtab );
     190                                }
     191                                argExpansions.emplace_front( std::move( funcE ) );
     192
     193                                for ( const CandidateRef & op : opFinder ) {
     194                                        try {
     195                                                // check if type is pointer-to-function
     196                                                const ast::Type * opResult = op->expr->result->stripReferences();
     197                                                if ( auto pointer = dynamic_cast< const ast::PointerType * >( opResult ) ) {
     198                                                        if ( auto function = pointer->base.as< ast::FunctionType >() ) {
     199                                                                CandidateRef newOp{ new Candidate{ *op} };
     200                                                                newOp->expr =
     201                                                                        referenceToRvalueConversion( newOp->expr, newOp->cost );
     202                                                                makeFunctionCandidates( newOp, function, argExpansions, found );
     203                                                        }
     204                                                }
     205                                        } catch ( SemanticErrorException & e ) { errors.append( e ); }
     206                                }
     207                        }
     208
     209                        // Implement SFINAE; resolution errors are only errors if there aren't any non-error
     210                        // candidates
     211                        if ( found.empty() && ! errors.isEmpty() ) { throw errors; }
     212
     213                        // Compute conversion costs
     214                        for ( CandidateRef & withFunc : found ) {
     215                                Cost cvtCost = computeApplicationConversionCost( withFunc, symtab );
     216
     217                                PRINT(
     218                                        auto appExpr = withFunc->expr.strict_as< ast::ApplicationExpr >();
     219                                        auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
     220                                        auto function = pointer->base.strict_as< ast::FunctionType >();
     221                                       
     222                                        std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl;
     223                                        std::cerr << "parameters are:" << std::endl;
     224                                        ast::printAll( std::cerr, function->params, 2 );
     225                                        std::cerr << "arguments are:" << std::endl;
     226                                        ast::printAll( std::cerr, appExpr->args, 2 );
     227                                        std::cerr << "bindings are:" << std::endl;
     228                                        ast::print( std::cerr, withFunc->env, 2 );
     229                                        std::cerr << "cost is: " << withFunc->cost << std::endl;
     230                                        std::cerr << "cost of conversion is:" << cvtCost << std::endl;
     231                                )
     232
     233                                if ( cvtCost != Cost::infinity ) {
     234                                        withFunc->cvtCost = cvtCost;
     235                                        candidates.emplace_back( std::move( withFunc ) );
     236                                }
     237                        }
     238                        found = std::move( candidates );
     239
     240                        // use a new list so that candidates are not examined by addAnonConversions twice
     241                        CandidateList winners = findMinCost( found );
     242                        promoteCvtCost( winners );
     243
     244                        // function may return a struct/union value, in which case we need to add candidates
     245                        // for implicit conversions to each of the anonymous members, which must happen after
     246                        // `findMinCost`, since anon conversions are never the cheapest
     247                        for ( const CandidateRef & c : winners ) {
     248                                addAnonConversions( c );
     249                        }
     250                        spliceBegin( candidates, winners );
     251
     252                        if ( candidates.empty() && targetType && ! targetType->isVoid() ) {
     253                                // If resolution is unsuccessful with a target type, try again without, since it
     254                                // will sometimes succeed when it wouldn't with a target type binding.
     255                                // For example:
     256                                //   forall( otype T ) T & ?[]( T *, ptrdiff_t );
     257                                //   const char * x = "hello world";
     258                                //   unsigned char ch = x[0];
     259                                // Fails with simple return type binding (xxx -- check this!) as follows:
     260                                // * T is bound to unsigned char
     261                                // * (x: const char *) is unified with unsigned char *, which fails
     262                                // xxx -- fix this better
     263                                targetType = nullptr;
     264                                postvisit( untypedExpr );
     265                        }
    71266                }
    72267
     
    440635        }
    441636
    442         /// Returns a list of alternatives with the minimum cost in the given list
    443         CandidateList findMinCost( const CandidateList & candidates ) {
    444                 CandidateList out;
    445                 Cost minCost = Cost::infinity;
    446                 for ( const CandidateRef & r : candidates ) {
    447                         if ( r->cost < minCost ) {
    448                                 minCost = r->cost;
    449                                 out.clear();
    450                                 out.emplace_back( r );
    451                         } else if ( r->cost == minCost ) {
    452                                 out.emplace_back( r );
    453                         }
    454                 }
    455                 return out;
    456         }
    457 
    458637} // anonymous namespace
    459638
Note: See TracChangeset for help on using the changeset viewer.