source: src/ResolvExpr/AlternativeFinder.cc@ 9f10c4b8

ADT aaron-thesis arm-eh ast-experimental cleanup-dtors deferred_resn demangler enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr new-env no_list persistent-indexer pthread-emulation qualifiedEnum resolv-new with_gc
Last change on this file since 9f10c4b8 was c93bc28, checked in by Rob Schluntz <rschlunt@…>, 8 years ago

Minor cleanup, debug statements

  • Property mode set to 100644
File size: 57.4 KB
RevLine 
[a32b204]1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
[6ed1d4b]7// AlternativeFinder.cc --
[a32b204]8//
9// Author : Richard C. Bilson
10// Created On : Sat May 16 23:52:08 2015
[a5f0529]11// Last Modified By : Andrew Beach
12// Last Modified On : Wed Jul 26 11:33:00 2017
13// Update Count : 31
[a32b204]14//
15
[51b73452]16#include <list>
17#include <iterator>
18#include <algorithm>
19#include <functional>
20#include <cassert>
[ebf5689]21#include <unordered_map>
22#include <utility>
23#include <vector>
[51b73452]24
25#include "AlternativeFinder.h"
26#include "Alternative.h"
27#include "Cost.h"
28#include "typeops.h"
29#include "Unify.h"
30#include "RenameVars.h"
31#include "SynTree/Type.h"
32#include "SynTree/Declaration.h"
33#include "SynTree/Expression.h"
34#include "SynTree/Initializer.h"
35#include "SynTree/Visitor.h"
36#include "SymTab/Indexer.h"
37#include "SymTab/Mangler.h"
38#include "SynTree/TypeSubstitution.h"
39#include "SymTab/Validate.h"
[6eb8948]40#include "Tuples/Tuples.h"
[141b786]41#include "Tuples/Explode.h"
[d3b7937]42#include "Common/utility.h"
[70f89d00]43#include "InitTweak/InitTweak.h"
[77971f6]44#include "InitTweak/GenInit.h"
[85517ddb]45#include "ResolveTypeof.h"
[722617d]46#include "Resolver.h"
[51b73452]47
[b87a5ed]48extern bool resolvep;
[6ed1d4b]49#define PRINT( text ) if ( resolvep ) { text }
[51b73452]50//#define DEBUG_COST
51
52namespace ResolvExpr {
[a32b204]53 Expression *resolveInVoidContext( Expression *expr, const SymTab::Indexer &indexer, TypeEnvironment &env ) {
54 CastExpr *castToVoid = new CastExpr( expr );
55
56 AlternativeFinder finder( indexer, env );
57 finder.findWithAdjustment( castToVoid );
58
59 // it's a property of the language that a cast expression has either 1 or 0 interpretations; if it has 0
60 // interpretations, an exception has already been thrown.
61 assert( finder.get_alternatives().size() == 1 );
62 CastExpr *newExpr = dynamic_cast< CastExpr* >( finder.get_alternatives().front().expr );
63 assert( newExpr );
64 env = finder.get_alternatives().front().env;
65 return newExpr->get_arg()->clone();
66 }
67
[908cc83]68 Cost sumCost( const AltList &in ) {
[89be1c68]69 Cost total = Cost::zero;
[908cc83]70 for ( AltList::const_iterator i = in.begin(); i != in.end(); ++i ) {
71 total += i->cost;
72 }
73 return total;
74 }
75
[a32b204]76 namespace {
77 void printAlts( const AltList &list, std::ostream &os, int indent = 0 ) {
78 for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) {
79 i->print( os, indent );
80 os << std::endl;
81 }
82 }
[d9a0e76]83
[a32b204]84 void makeExprList( const AltList &in, std::list< Expression* > &out ) {
85 for ( AltList::const_iterator i = in.begin(); i != in.end(); ++i ) {
86 out.push_back( i->expr->clone() );
87 }
88 }
[d9a0e76]89
[a32b204]90 struct PruneStruct {
91 bool isAmbiguous;
92 AltList::iterator candidate;
93 PruneStruct() {}
94 PruneStruct( AltList::iterator candidate ): isAmbiguous( false ), candidate( candidate ) {}
95 };
96
[0f19d763]97 /// Prunes a list of alternatives down to those that have the minimum conversion cost for a given return type; skips ambiguous interpretations
[a32b204]98 template< typename InputIterator, typename OutputIterator >
[d7dc824]99 void pruneAlternatives( InputIterator begin, InputIterator end, OutputIterator out ) {
[a32b204]100 // select the alternatives that have the minimum conversion cost for a particular set of result types
101 std::map< std::string, PruneStruct > selected;
102 for ( AltList::iterator candidate = begin; candidate != end; ++candidate ) {
103 PruneStruct current( candidate );
104 std::string mangleName;
[906e24d]105 {
106 Type * newType = candidate->expr->get_result()->clone();
[a32b204]107 candidate->env.apply( newType );
[906e24d]108 mangleName = SymTab::Mangler::mangle( newType );
[a32b204]109 delete newType;
110 }
111 std::map< std::string, PruneStruct >::iterator mapPlace = selected.find( mangleName );
112 if ( mapPlace != selected.end() ) {
113 if ( candidate->cost < mapPlace->second.candidate->cost ) {
114 PRINT(
[6ed1d4b]115 std::cerr << "cost " << candidate->cost << " beats " << mapPlace->second.candidate->cost << std::endl;
[7c64920]116 )
[0f19d763]117 selected[ mangleName ] = current;
[a32b204]118 } else if ( candidate->cost == mapPlace->second.candidate->cost ) {
119 PRINT(
[6ed1d4b]120 std::cerr << "marking ambiguous" << std::endl;
[7c64920]121 )
[0f19d763]122 mapPlace->second.isAmbiguous = true;
[a32b204]123 }
124 } else {
125 selected[ mangleName ] = current;
126 }
127 }
[d9a0e76]128
129 PRINT(
[6ed1d4b]130 std::cerr << "there are " << selected.size() << " alternatives before elimination" << std::endl;
[7c64920]131 )
[a32b204]132
[0f19d763]133 // accept the alternatives that were unambiguous
134 for ( std::map< std::string, PruneStruct >::iterator target = selected.begin(); target != selected.end(); ++target ) {
135 if ( ! target->second.isAmbiguous ) {
136 Alternative &alt = *target->second.candidate;
[906e24d]137 alt.env.applyFree( alt.expr->get_result() );
[0f19d763]138 *out++ = alt;
[a32b204]139 }
[0f19d763]140 }
[d9a0e76]141 }
[a32b204]142
143 void renameTypes( Expression *expr ) {
[906e24d]144 expr->get_result()->accept( global_renamer );
[e76acbe]145 }
[b1bead1]146
147 void referenceToRvalueConversion( Expression *& expr ) {
148 if ( dynamic_cast< ReferenceType * >( expr->get_result() ) ) {
149 // cast away reference from expr
150 expr = new CastExpr( expr, expr->get_result()->stripReferences()->clone() );
151 }
152 }
153 } // namespace
[d9a0e76]154
[a32b204]155 template< typename InputIterator, typename OutputIterator >
156 void AlternativeFinder::findSubExprs( InputIterator begin, InputIterator end, OutputIterator out ) {
157 while ( begin != end ) {
158 AlternativeFinder finder( indexer, env );
159 finder.findWithAdjustment( *begin );
160 // XXX either this
161 //Designators::fixDesignations( finder, (*begin++)->get_argName() );
162 // or XXX this
163 begin++;
164 PRINT(
[6ed1d4b]165 std::cerr << "findSubExprs" << std::endl;
166 printAlts( finder.alternatives, std::cerr );
[7c64920]167 )
[0f19d763]168 *out++ = finder;
[a32b204]169 }
[d9a0e76]170 }
171
[a32b204]172 AlternativeFinder::AlternativeFinder( const SymTab::Indexer &indexer, const TypeEnvironment &env )
173 : indexer( indexer ), env( env ) {
[d9a0e76]174 }
[51b73452]175
[b6fe7e6]176 void AlternativeFinder::find( Expression *expr, bool adjust, bool prune ) {
[a32b204]177 expr->accept( *this );
178 if ( alternatives.empty() ) {
179 throw SemanticError( "No reasonable alternatives for expression ", expr );
180 }
181 for ( AltList::iterator i = alternatives.begin(); i != alternatives.end(); ++i ) {
182 if ( adjust ) {
[906e24d]183 adjustExprType( i->expr->get_result(), i->env, indexer );
[a32b204]184 }
185 }
[b6fe7e6]186 if ( prune ) {
187 PRINT(
188 std::cerr << "alternatives before prune:" << std::endl;
189 printAlts( alternatives, std::cerr );
190 )
191 AltList::iterator oldBegin = alternatives.begin();
[d7dc824]192 pruneAlternatives( alternatives.begin(), alternatives.end(), front_inserter( alternatives ) );
[b6fe7e6]193 if ( alternatives.begin() == oldBegin ) {
194 std::ostringstream stream;
195 AltList winners;
196 findMinCost( alternatives.begin(), alternatives.end(), back_inserter( winners ) );
[5a824c2]197 stream << "Can't choose between " << winners.size() << " alternatives for expression ";
198 expr->print( stream );
199 stream << "Alternatives are:";
[b6fe7e6]200 printAlts( winners, stream, 8 );
201 throw SemanticError( stream.str() );
202 }
203 alternatives.erase( oldBegin, alternatives.end() );
204 PRINT(
205 std::cerr << "there are " << alternatives.size() << " alternatives after elimination" << std::endl;
206 )
[a32b204]207 }
[8e9cbb2]208
[64ac636]209 // Central location to handle gcc extension keyword, etc. for all expression types.
[8e9cbb2]210 for ( Alternative &iter: alternatives ) {
211 iter.expr->set_extension( expr->get_extension() );
[64ac636]212 iter.expr->location = expr->location;
[8e9cbb2]213 } // for
[0f19d763]214 }
[d9a0e76]215
[b6fe7e6]216 void AlternativeFinder::findWithAdjustment( Expression *expr, bool prune ) {
217 find( expr, true, prune );
[d9a0e76]218 }
[a32b204]219
[4b0f997]220 void AlternativeFinder::addAnonConversions( const Alternative & alt ) {
221 // adds anonymous member interpretations whenever an aggregate value type is seen.
[d1685588]222 // it's okay for the aggregate expression to have reference type -- cast it to the base type to treat the aggregate as the referenced value
223 std::unique_ptr<Expression> aggrExpr( alt.expr->clone() );
224 alt.env.apply( aggrExpr->get_result() );
225 Type * aggrType = aggrExpr->get_result();
226 if ( dynamic_cast< ReferenceType * >( aggrType ) ) {
227 aggrType = aggrType->stripReferences();
228 aggrExpr.reset( new CastExpr( aggrExpr.release(), aggrType->clone() ) );
229 }
230
231 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) {
[4b0f997]232 NameExpr nameExpr( "" );
[d1685588]233 addAggMembers( structInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, &nameExpr );
234 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) {
[4b0f997]235 NameExpr nameExpr( "" );
[d1685588]236 addAggMembers( unionInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, &nameExpr );
[4b0f997]237 } // if
238 }
[77971f6]239
[a32b204]240 template< typename StructOrUnionType >
[add7117]241 void AlternativeFinder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
[bf32bb8]242 // by this point, member must be a name expr
[c93bc28]243 NameExpr * nameExpr = dynamic_cast< NameExpr * >( member );
244 if ( ! nameExpr ) return;
[bf32bb8]245 const std::string & name = nameExpr->get_name();
246 std::list< Declaration* > members;
247 aggInst->lookup( name, members );
[4b0f997]248
[bf32bb8]249 for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) {
250 if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) {
[d9fa60a]251 alternatives.push_back( Alternative( new MemberExpr( dwt, expr->clone() ), env, newCost ) );
[bf32bb8]252 renameTypes( alternatives.back().expr );
[4b0f997]253 addAnonConversions( alternatives.back() ); // add anonymous member interpretations whenever an aggregate value type is seen as a member expression.
[bf32bb8]254 } else {
255 assert( false );
[a32b204]256 }
257 }
[d9a0e76]258 }
[a32b204]259
[848ce71]260 void AlternativeFinder::addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
261 if ( ConstantExpr * constantExpr = dynamic_cast< ConstantExpr * >( member ) ) {
262 // get the value of the constant expression as an int, must be between 0 and the length of the tuple type to have meaning
263 // xxx - this should be improved by memoizing the value of constant exprs
264 // during parsing and reusing that information here.
265 std::stringstream ss( constantExpr->get_constant()->get_value() );
[c93bc28]266 int val = 0;
[848ce71]267 std::string tmp;
268 if ( ss >> val && ! (ss >> tmp) ) {
269 if ( val >= 0 && (unsigned int)val < tupleType->size() ) {
270 alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) );
271 } // if
272 } // if
[141b786]273 } else if ( NameExpr * nameExpr = dynamic_cast< NameExpr * >( member ) ) {
274 // xxx - temporary hack until 0/1 are int constants
275 if ( nameExpr->get_name() == "0" || nameExpr->get_name() == "1" ) {
276 std::stringstream ss( nameExpr->get_name() );
277 int val;
278 ss >> val;
279 alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) );
280 }
[848ce71]281 } // if
282 }
283
[a32b204]284 void AlternativeFinder::visit( ApplicationExpr *applicationExpr ) {
285 alternatives.push_back( Alternative( applicationExpr->clone(), env, Cost::zero ) );
[d9a0e76]286 }
287
[a32b204]288 Cost computeConversionCost( Alternative &alt, const SymTab::Indexer &indexer ) {
[8f7cea1]289 ApplicationExpr *appExpr = safe_dynamic_cast< ApplicationExpr* >( alt.expr );
[906e24d]290 PointerType *pointer = safe_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
[8f7cea1]291 FunctionType *function = safe_dynamic_cast< FunctionType* >( pointer->get_base() );
[a32b204]292
[89be1c68]293 Cost convCost = Cost::zero;
[a32b204]294 std::list< DeclarationWithType* >& formals = function->get_parameters();
295 std::list< DeclarationWithType* >::iterator formal = formals.begin();
296 std::list< Expression* >& actuals = appExpr->get_args();
[0362d42]297
[a32b204]298 for ( std::list< Expression* >::iterator actualExpr = actuals.begin(); actualExpr != actuals.end(); ++actualExpr ) {
[53e3b4a]299 Type * actualType = (*actualExpr)->get_result();
[a32b204]300 PRINT(
[6ed1d4b]301 std::cerr << "actual expression:" << std::endl;
302 (*actualExpr)->print( std::cerr, 8 );
303 std::cerr << "--- results are" << std::endl;
[53e3b4a]304 actualType->print( std::cerr, 8 );
[7c64920]305 )
[89be1c68]306 Cost actualCost = Cost::zero;
[53e3b4a]307 if ( formal == formals.end() ) {
308 if ( function->get_isVarArgs() ) {
[89be1c68]309 convCost.incUnsafe();
[b1bead1]310 // convert reference-typed expressions to value-typed expressions
311 referenceToRvalueConversion( *actualExpr );
[53e3b4a]312 continue;
313 } else {
314 return Cost::infinity;
[7c64920]315 }
[53e3b4a]316 }
317 Type * formalType = (*formal)->get_type();
318 PRINT(
319 std::cerr << std::endl << "converting ";
320 actualType->print( std::cerr, 8 );
321 std::cerr << std::endl << " to ";
322 formalType->print( std::cerr, 8 );
[a61ad31]323 std::cerr << std::endl << "environment is: ";
324 alt.env.print( std::cerr, 8 );
325 std::cerr << std::endl;
[53e3b4a]326 )
327 Cost newCost = conversionCost( actualType, formalType, indexer, alt.env );
328 PRINT(
329 std::cerr << std::endl << "cost is" << newCost << std::endl;
330 )
[a32b204]331
[53e3b4a]332 if ( newCost == Cost::infinity ) {
333 return newCost;
[a32b204]334 }
[53e3b4a]335 convCost += newCost;
336 actualCost += newCost;
[89be1c68]337 if ( actualCost != Cost::zero ) {
[53e3b4a]338 Type *newType = formalType->clone();
339 alt.env.apply( newType );
340 *actualExpr = new CastExpr( *actualExpr, newType );
[a32b204]341 }
[89be1c68]342 convCost.incPoly( polyCost( formalType, alt.env, indexer ) + polyCost( actualType, alt.env, indexer ) );
[53e3b4a]343 ++formal; // can't be in for-loop update because of the continue
[d9a0e76]344 }
[a32b204]345 if ( formal != formals.end() ) {
346 return Cost::infinity;
[d9a0e76]347 }
348
[a32b204]349 for ( InferredParams::const_iterator assert = appExpr->get_inferParams().begin(); assert != appExpr->get_inferParams().end(); ++assert ) {
350 PRINT(
[6ed1d4b]351 std::cerr << std::endl << "converting ";
352 assert->second.actualType->print( std::cerr, 8 );
353 std::cerr << std::endl << " to ";
354 assert->second.formalType->print( std::cerr, 8 );
[02cea2d]355 )
356 Cost newCost = conversionCost( assert->second.actualType, assert->second.formalType, indexer, alt.env );
[a32b204]357 PRINT(
[6ed1d4b]358 std::cerr << std::endl << "cost of conversion is " << newCost << std::endl;
[02cea2d]359 )
360 if ( newCost == Cost::infinity ) {
361 return newCost;
362 }
[a32b204]363 convCost += newCost;
[89be1c68]364 convCost.incPoly( polyCost( assert->second.formalType, alt.env, indexer ) + polyCost( assert->second.actualType, alt.env, indexer ) );
[a32b204]365 }
[d9a0e76]366
[a32b204]367 return convCost;
368 }
[d9a0e76]369
[8c84ebd]370 /// Adds type variables to the open variable set and marks their assertions
[a32b204]371 void makeUnifiableVars( Type *type, OpenVarSet &unifiableVars, AssertionSet &needAssertions ) {
[8c49c0e]372 for ( Type::ForallList::const_iterator tyvar = type->get_forall().begin(); tyvar != type->get_forall().end(); ++tyvar ) {
[2c57025]373 unifiableVars[ (*tyvar)->get_name() ] = TypeDecl::Data{ *tyvar };
[a32b204]374 for ( std::list< DeclarationWithType* >::iterator assert = (*tyvar)->get_assertions().begin(); assert != (*tyvar)->get_assertions().end(); ++assert ) {
[6c3a988f]375 needAssertions[ *assert ].isUsed = true;
[a32b204]376 }
[d9a0e76]377/// needAssertions.insert( needAssertions.end(), (*tyvar)->get_assertions().begin(), (*tyvar)->get_assertions().end() );
378 }
379 }
[a32b204]380
[aefcc3b]381 /// instantiate a single argument by matching actuals from [actualIt, actualEnd) against formalType,
382 /// producing expression(s) in out and their total cost in cost.
383 template< typename AltIterator, typename OutputIterator >
384 bool instantiateArgument( Type * formalType, Initializer * defaultValue, AltIterator & actualIt, AltIterator actualEnd, OpenVarSet & openVars, TypeEnvironment & resultEnv, AssertionSet & resultNeed, AssertionSet & resultHave, const SymTab::Indexer & indexer, Cost & cost, OutputIterator out ) {
385 if ( TupleType * tupleType = dynamic_cast< TupleType * >( formalType ) ) {
386 // formalType is a TupleType - group actuals into a TupleExpr whose type unifies with the TupleType
[907eccb]387 std::list< Expression * > exprs;
[aefcc3b]388 for ( Type * type : *tupleType ) {
[907eccb]389 if ( ! instantiateArgument( type, defaultValue, actualIt, actualEnd, openVars, resultEnv, resultNeed, resultHave, indexer, cost, back_inserter( exprs ) ) ) {
390 deleteAll( exprs );
[aefcc3b]391 return false;
392 }
393 }
[907eccb]394 *out++ = new TupleExpr( exprs );
[4c8621ac]395 } else if ( TypeInstType * ttype = Tuples::isTtype( formalType ) ) {
396 // xxx - mixing default arguments with variadic??
397 std::list< Expression * > exprs;
398 for ( ; actualIt != actualEnd; ++actualIt ) {
399 exprs.push_back( actualIt->expr->clone() );
400 cost += actualIt->cost;
[53e3b4a]401 }
[4c8621ac]402 Expression * arg = nullptr;
403 if ( exprs.size() == 1 && Tuples::isTtype( exprs.front()->get_result() ) ) {
404 // the case where a ttype value is passed directly is special, e.g. for argument forwarding purposes
405 // xxx - what if passing multiple arguments, last of which is ttype?
406 // xxx - what would happen if unify was changed so that unifying tuple types flattened both before unifying lists? then pass in TupleType(ttype) below.
407 arg = exprs.front();
408 } else {
409 arg = new TupleExpr( exprs );
410 }
411 assert( arg && arg->get_result() );
412 if ( ! unify( ttype, arg->get_result(), resultEnv, resultNeed, resultHave, openVars, indexer ) ) {
413 return false;
414 }
415 *out++ = arg;
416 } else if ( actualIt != actualEnd ) {
[aefcc3b]417 // both actualType and formalType are atomic (non-tuple) types - if they unify
418 // then accept actual as an argument, otherwise return false (fail to instantiate argument)
419 Expression * actual = actualIt->expr;
420 Type * actualType = actual->get_result();
[a61ad31]421
[aefcc3b]422 PRINT(
423 std::cerr << "formal type is ";
424 formalType->print( std::cerr );
425 std::cerr << std::endl << "actual type is ";
426 actualType->print( std::cerr );
427 std::cerr << std::endl;
428 )
429 if ( ! unify( formalType, actualType, resultEnv, resultNeed, resultHave, openVars, indexer ) ) {
[d1685588]430 // std::cerr << "unify failed" << std::endl;
[aefcc3b]431 return false;
432 }
433 // move the expression from the alternative to the output iterator
434 *out++ = actual;
435 actualIt->expr = nullptr;
436 cost += actualIt->cost;
437 ++actualIt;
438 } else {
439 // End of actuals - Handle default values
440 if ( SingleInit *si = dynamic_cast<SingleInit *>( defaultValue )) {
[064cb18]441 if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( si->get_value() ) ) {
442 // so far, only constant expressions are accepted as default values
443 if ( ConstantExpr *cnstexpr = dynamic_cast<ConstantExpr *>( castExpr->get_arg() ) ) {
444 if ( Constant *cnst = dynamic_cast<Constant *>( cnstexpr->get_constant() ) ) {
445 if ( unify( formalType, cnst->get_type(), resultEnv, resultNeed, resultHave, openVars, indexer ) ) {
446 *out++ = cnstexpr->clone();
447 return true;
448 } // if
[aefcc3b]449 } // if
450 } // if
[064cb18]451 }
[aefcc3b]452 } // if
453 return false;
454 } // if
455 return true;
456 }
457
458 bool AlternativeFinder::instantiateFunction( std::list< DeclarationWithType* >& formals, const AltList &actuals, bool isVarArgs, OpenVarSet& openVars, TypeEnvironment &resultEnv, AssertionSet &resultNeed, AssertionSet &resultHave, AltList & out ) {
[a32b204]459 simpleCombineEnvironments( actuals.begin(), actuals.end(), resultEnv );
460 // make sure we don't widen any existing bindings
461 for ( TypeEnvironment::iterator i = resultEnv.begin(); i != resultEnv.end(); ++i ) {
462 i->allowWidening = false;
463 }
464 resultEnv.extractOpenVars( openVars );
465
[aefcc3b]466 // flatten actuals so that each actual has an atomic (non-tuple) type
467 AltList exploded;
[77971f6]468 Tuples::explode( actuals, indexer, back_inserter( exploded ) );
[aefcc3b]469
470 AltList::iterator actualExpr = exploded.begin();
471 AltList::iterator actualEnd = exploded.end();
472 for ( DeclarationWithType * formal : formals ) {
473 // match flattened actuals with formal parameters - actuals will be grouped to match
474 // with formals as appropriate
[89be1c68]475 Cost cost = Cost::zero;
[aefcc3b]476 std::list< Expression * > newExprs;
477 ObjectDecl * obj = safe_dynamic_cast< ObjectDecl * >( formal );
478 if ( ! instantiateArgument( obj->get_type(), obj->get_init(), actualExpr, actualEnd, openVars, resultEnv, resultNeed, resultHave, indexer, cost, back_inserter( newExprs ) ) ) {
479 deleteAll( newExprs );
480 return false;
[a32b204]481 }
[aefcc3b]482 // success - produce argument as a new alternative
483 assert( newExprs.size() == 1 );
484 out.push_back( Alternative( newExprs.front(), resultEnv, cost ) );
[a32b204]485 }
[aefcc3b]486 if ( actualExpr != actualEnd ) {
487 // there are still actuals remaining, but we've run out of formal parameters to match against
488 // this is okay only if the function is variadic
489 if ( ! isVarArgs ) {
490 return false;
491 }
492 out.splice( out.end(), exploded, actualExpr, actualEnd );
[a32b204]493 }
494 return true;
[d9a0e76]495 }
[51b73452]496
[89b686a]497 // /// Map of declaration uniqueIds (intended to be the assertions in an AssertionSet) to their parents and the number of times they've been included
498 //typedef std::unordered_map< UniqueId, std::unordered_map< UniqueId, unsigned > > AssertionParentSet;
[79970ed]499
[a1d7679]500 static const int recursionLimit = /*10*/ 4; ///< Limit to depth of recursion satisfaction
[89b686a]501 //static const unsigned recursionParentLimit = 1; ///< Limit to the number of times an assertion can recursively use itself
[51b73452]502
[a32b204]503 void addToIndexer( AssertionSet &assertSet, SymTab::Indexer &indexer ) {
504 for ( AssertionSet::iterator i = assertSet.begin(); i != assertSet.end(); ++i ) {
[6c3a988f]505 if ( i->second.isUsed ) {
[a32b204]506 i->first->accept( indexer );
507 }
508 }
[d9a0e76]509 }
[79970ed]510
[a32b204]511 template< typename ForwardIterator, typename OutputIterator >
[79970ed]512 void inferRecursive( ForwardIterator begin, ForwardIterator end, const Alternative &newAlt, OpenVarSet &openVars, const SymTab::Indexer &decls, const AssertionSet &newNeed, /*const AssertionParentSet &needParents,*/
[ebf5689]513 int level, const SymTab::Indexer &indexer, OutputIterator out ) {
[a32b204]514 if ( begin == end ) {
515 if ( newNeed.empty() ) {
[6c3a988f]516 PRINT(
517 std::cerr << "all assertions satisfied, output alternative: ";
518 newAlt.print( std::cerr );
519 std::cerr << std::endl;
520 );
[a32b204]521 *out++ = newAlt;
522 return;
523 } else if ( level >= recursionLimit ) {
524 throw SemanticError( "Too many recursive assertions" );
525 } else {
526 AssertionSet newerNeed;
527 PRINT(
528 std::cerr << "recursing with new set:" << std::endl;
529 printAssertionSet( newNeed, std::cerr, 8 );
[7c64920]530 )
[89b686a]531 inferRecursive( newNeed.begin(), newNeed.end(), newAlt, openVars, decls, newerNeed, /*needParents,*/ level+1, indexer, out );
[a32b204]532 return;
533 }
534 }
535
536 ForwardIterator cur = begin++;
[6c3a988f]537 if ( ! cur->second.isUsed ) {
[89b686a]538 inferRecursive( begin, end, newAlt, openVars, decls, newNeed, /*needParents,*/ level, indexer, out );
[7933351]539 return; // xxx - should this continue? previously this wasn't here, and it looks like it should be
[a32b204]540 }
541 DeclarationWithType *curDecl = cur->first;
[7933351]542
[d9a0e76]543 PRINT(
[a32b204]544 std::cerr << "inferRecursive: assertion is ";
545 curDecl->print( std::cerr );
546 std::cerr << std::endl;
[7c64920]547 )
[0f19d763]548 std::list< DeclarationWithType* > candidates;
[a32b204]549 decls.lookupId( curDecl->get_name(), candidates );
[6ed1d4b]550/// if ( candidates.empty() ) { std::cerr << "no candidates!" << std::endl; }
[a32b204]551 for ( std::list< DeclarationWithType* >::const_iterator candidate = candidates.begin(); candidate != candidates.end(); ++candidate ) {
552 PRINT(
[6ed1d4b]553 std::cerr << "inferRecursive: candidate is ";
554 (*candidate)->print( std::cerr );
555 std::cerr << std::endl;
[7c64920]556 )
[79970ed]557
[0f19d763]558 AssertionSet newHave, newerNeed( newNeed );
[a32b204]559 TypeEnvironment newEnv( newAlt.env );
560 OpenVarSet newOpenVars( openVars );
561 Type *adjType = (*candidate)->get_type()->clone();
562 adjustExprType( adjType, newEnv, indexer );
563 adjType->accept( global_renamer );
564 PRINT(
565 std::cerr << "unifying ";
566 curDecl->get_type()->print( std::cerr );
567 std::cerr << " with ";
568 adjType->print( std::cerr );
569 std::cerr << std::endl;
[7c64920]570 )
[0f19d763]571 if ( unify( curDecl->get_type(), adjType, newEnv, newerNeed, newHave, newOpenVars, indexer ) ) {
572 PRINT(
573 std::cerr << "success!" << std::endl;
[a32b204]574 )
[0f19d763]575 SymTab::Indexer newDecls( decls );
576 addToIndexer( newHave, newDecls );
577 Alternative newerAlt( newAlt );
578 newerAlt.env = newEnv;
579 assert( (*candidate)->get_uniqueId() );
[22cad76]580 DeclarationWithType *candDecl = static_cast< DeclarationWithType* >( Declaration::declFromId( (*candidate)->get_uniqueId() ) );
[6c3a988f]581
582 // everything with an empty idChain was pulled in by the current assertion.
583 // add current assertion's idChain + current assertion's ID so that the correct inferParameters can be found.
584 for ( auto & a : newerNeed ) {
585 if ( a.second.idChain.empty() ) {
586 a.second.idChain = cur->second.idChain;
587 a.second.idChain.push_back( curDecl->get_uniqueId() );
588 }
589 }
590
[89b686a]591 //AssertionParentSet newNeedParents( needParents );
[22cad76]592 // skip repeatingly-self-recursive assertion satisfaction
[89b686a]593 // DOESN'T WORK: grandchild nodes conflict with their cousins
594 //if ( newNeedParents[ curDecl->get_uniqueId() ][ candDecl->get_uniqueId() ]++ > recursionParentLimit ) continue;
[22cad76]595 Expression *varExpr = new VariableExpr( candDecl );
[906e24d]596 delete varExpr->get_result();
597 varExpr->set_result( adjType->clone() );
[0f19d763]598 PRINT(
[6ed1d4b]599 std::cerr << "satisfying assertion " << curDecl->get_uniqueId() << " ";
600 curDecl->print( std::cerr );
601 std::cerr << " with declaration " << (*candidate)->get_uniqueId() << " ";
602 (*candidate)->print( std::cerr );
603 std::cerr << std::endl;
[7c64920]604 )
[0f19d763]605 ApplicationExpr *appExpr = static_cast< ApplicationExpr* >( newerAlt.expr );
[6c3a988f]606 // follow the current assertion's ID chain to find the correct set of inferred parameters to add the candidate to (i.e. the set of inferred parameters belonging to the entity which requested the assertion parameter).
607 InferredParams * inferParameters = &appExpr->get_inferParams();
608 for ( UniqueId id : cur->second.idChain ) {
609 inferParameters = (*inferParameters)[ id ].inferParams.get();
610 }
[0f19d763]611 // XXX: this is a memory leak, but adjType can't be deleted because it might contain assertions
[6c3a988f]612 (*inferParameters)[ curDecl->get_uniqueId() ] = ParamEntry( (*candidate)->get_uniqueId(), adjType->clone(), curDecl->get_type()->clone(), varExpr );
[89b686a]613 inferRecursive( begin, end, newerAlt, newOpenVars, newDecls, newerNeed, /*newNeedParents,*/ level, indexer, out );
[0f19d763]614 } else {
615 delete adjType;
616 }
[a32b204]617 }
[d9a0e76]618 }
619
[a32b204]620 template< typename OutputIterator >
621 void AlternativeFinder::inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out ) {
[d9a0e76]622// PRINT(
[6ed1d4b]623// std::cerr << "inferParameters: assertions needed are" << std::endl;
624// printAll( need, std::cerr, 8 );
[d9a0e76]625// )
[a32b204]626 SymTab::Indexer decls( indexer );
[e4d829b]627 // PRINT(
628 // std::cerr << "============= original indexer" << std::endl;
629 // indexer.print( std::cerr );
630 // std::cerr << "============= new indexer" << std::endl;
631 // decls.print( std::cerr );
632 // )
[0f19d763]633 addToIndexer( have, decls );
[a32b204]634 AssertionSet newNeed;
[89b686a]635 //AssertionParentSet needParents;
[74b007ba]636 PRINT(
637 std::cerr << "env is: " << std::endl;
638 newAlt.env.print( std::cerr, 0 );
639 std::cerr << std::endl;
640 )
641
[89b686a]642 inferRecursive( need.begin(), need.end(), newAlt, openVars, decls, newNeed, /*needParents,*/ 0, indexer, out );
[d9a0e76]643// PRINT(
[6ed1d4b]644// std::cerr << "declaration 14 is ";
[d9a0e76]645// Declaration::declFromId
646// *out++ = newAlt;
647// )
648 }
649
[a32b204]650 template< typename OutputIterator >
[aefcc3b]651 void AlternativeFinder::makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const AltList &actualAlt, OutputIterator out ) {
[a32b204]652 OpenVarSet openVars;
653 AssertionSet resultNeed, resultHave;
654 TypeEnvironment resultEnv;
655 makeUnifiableVars( funcType, openVars, resultNeed );
[7f623d6f]656 resultEnv.add( funcType->get_forall() ); // add all type variables as open variables now so that those not used in the parameter list are still considered open
[aefcc3b]657 AltList instantiatedActuals; // filled by instantiate function
[53e3b4a]658 if ( targetType && ! targetType->isVoid() && ! funcType->get_returnVals().empty() ) {
[ea83e00a]659 // attempt to narrow based on expected target type
660 Type * returnType = funcType->get_returnVals().front()->get_type();
661 if ( ! unify( returnType, targetType, resultEnv, resultNeed, resultHave, openVars, indexer ) ) {
662 // unification failed, don't pursue this alternative
663 return;
664 }
665 }
666
[aefcc3b]667 if ( instantiateFunction( funcType->get_parameters(), actualAlt, funcType->get_isVarArgs(), openVars, resultEnv, resultNeed, resultHave, instantiatedActuals ) ) {
[a32b204]668 ApplicationExpr *appExpr = new ApplicationExpr( func.expr->clone() );
[aefcc3b]669 Alternative newAlt( appExpr, resultEnv, sumCost( instantiatedActuals ) );
670 makeExprList( instantiatedActuals, appExpr->get_args() );
[a32b204]671 PRINT(
[a61ad31]672 std::cerr << "instantiate function success: " << appExpr << std::endl;
[6ed1d4b]673 std::cerr << "need assertions:" << std::endl;
674 printAssertionSet( resultNeed, std::cerr, 8 );
[7c64920]675 )
[0f19d763]676 inferParameters( resultNeed, resultHave, newAlt, openVars, out );
[d9a0e76]677 }
678 }
679
[a32b204]680 void AlternativeFinder::visit( UntypedExpr *untypedExpr ) {
681 bool doneInit = false;
682 AlternativeFinder funcOpFinder( indexer, env );
[d9a0e76]683
[6ed1d4b]684 AlternativeFinder funcFinder( indexer, env );
685
686 {
[70f89d00]687 std::string fname = InitTweak::getFunctionName( untypedExpr );
688 if ( fname == "&&" ) {
[2871210]689 VoidType v = Type::Qualifiers(); // resolve to type void *
690 PointerType pt( Type::Qualifiers(), v.clone() );
691 UntypedExpr *vexpr = untypedExpr->clone();
[906e24d]692 vexpr->set_result( pt.clone() );
[89be1c68]693 alternatives.push_back( Alternative( vexpr, env, Cost::zero) );
[a32b204]694 return;
695 }
696 }
[d9a0e76]697
[a32b204]698 funcFinder.findWithAdjustment( untypedExpr->get_function() );
699 std::list< AlternativeFinder > argAlternatives;
700 findSubExprs( untypedExpr->begin_args(), untypedExpr->end_args(), back_inserter( argAlternatives ) );
[d9a0e76]701
[a32b204]702 std::list< AltList > possibilities;
703 combos( argAlternatives.begin(), argAlternatives.end(), back_inserter( possibilities ) );
[d9a0e76]704
[5af62f1]705 // take care of possible tuple assignments
706 // if not tuple assignment, assignment is taken care of as a normal function call
707 Tuples::handleTupleAssignment( *this, untypedExpr, possibilities );
[d9a0e76]708
[a32b204]709 AltList candidates;
[91b8a17]710 SemanticError errors;
[b1bead1]711 for ( AltList::iterator func = funcFinder.alternatives.begin(); func != funcFinder.alternatives.end(); ++func ) {
[91b8a17]712 try {
713 PRINT(
714 std::cerr << "working on alternative: " << std::endl;
715 func->print( std::cerr, 8 );
716 )
717 // check if the type is pointer to function
[b1bead1]718 if ( PointerType *pointer = dynamic_cast< PointerType* >( func->expr->get_result()->stripReferences() ) ) {
[91b8a17]719 if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() ) ) {
[b1bead1]720 referenceToRvalueConversion( func->expr );
[91b8a17]721 for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) {
722 // XXX
723 //Designators::check_alternative( function, *actualAlt );
724 makeFunctionAlternatives( *func, function, *actualAlt, std::back_inserter( candidates ) );
725 }
[b1bead1]726 }
727 } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr->get_result()->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer)
728 referenceToRvalueConversion( func->expr );
729 EqvClass eqvClass;
730 if ( func->env.lookup( typeInst->get_name(), eqvClass ) && eqvClass.type ) {
731 if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass.type ) ) {
732 for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) {
733 makeFunctionAlternatives( *func, function, *actualAlt, std::back_inserter( candidates ) );
734 } // for
[a32b204]735 } // if
736 } // if
[91b8a17]737 } else {
738 // seek a function operator that's compatible
739 if ( ! doneInit ) {
740 doneInit = true;
741 NameExpr *opExpr = new NameExpr( "?()" );
742 try {
743 funcOpFinder.findWithAdjustment( opExpr );
744 } catch( SemanticError &e ) {
745 // it's ok if there aren't any defined function ops
746 }
747 PRINT(
748 std::cerr << "known function ops:" << std::endl;
749 printAlts( funcOpFinder.alternatives, std::cerr, 8 );
750 )
[a32b204]751 }
752
[b1bead1]753 for ( AltList::iterator funcOp = funcOpFinder.alternatives.begin(); funcOp != funcOpFinder.alternatives.end(); ++funcOp ) {
[91b8a17]754 // check if the type is pointer to function
[b1bead1]755 if ( PointerType *pointer = dynamic_cast< PointerType* >( funcOp->expr->get_result()->stripReferences() ) ) {
[91b8a17]756 if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() ) ) {
[b1bead1]757 referenceToRvalueConversion( funcOp->expr );
[91b8a17]758 for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) {
759 AltList currentAlt;
760 currentAlt.push_back( *func );
761 currentAlt.insert( currentAlt.end(), actualAlt->begin(), actualAlt->end() );
762 makeFunctionAlternatives( *funcOp, function, currentAlt, std::back_inserter( candidates ) );
763 } // for
764 } // if
[a32b204]765 } // if
[91b8a17]766 } // for
767 } // if
768 } catch ( SemanticError &e ) {
769 errors.append( e );
770 }
[a32b204]771 } // for
772
[91b8a17]773 // Implement SFINAE; resolution errors are only errors if there aren't any non-erroneous resolutions
774 if ( candidates.empty() && ! errors.isEmpty() ) { throw errors; }
775
[4b0f997]776 // compute conversionsion costs
[a32b204]777 for ( AltList::iterator withFunc = candidates.begin(); withFunc != candidates.end(); ++withFunc ) {
778 Cost cvtCost = computeConversionCost( *withFunc, indexer );
779
780 PRINT(
[8f7cea1]781 ApplicationExpr *appExpr = safe_dynamic_cast< ApplicationExpr* >( withFunc->expr );
[906e24d]782 PointerType *pointer = safe_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
[8f7cea1]783 FunctionType *function = safe_dynamic_cast< FunctionType* >( pointer->get_base() );
[a61ad31]784 std::cerr << "Case +++++++++++++ " << appExpr->get_function() << std::endl;
[6ed1d4b]785 std::cerr << "formals are:" << std::endl;
786 printAll( function->get_parameters(), std::cerr, 8 );
787 std::cerr << "actuals are:" << std::endl;
788 printAll( appExpr->get_args(), std::cerr, 8 );
789 std::cerr << "bindings are:" << std::endl;
790 withFunc->env.print( std::cerr, 8 );
791 std::cerr << "cost of conversion is:" << cvtCost << std::endl;
[7c64920]792 )
793 if ( cvtCost != Cost::infinity ) {
794 withFunc->cvtCost = cvtCost;
795 alternatives.push_back( *withFunc );
796 } // if
[a32b204]797 } // for
[4b0f997]798
[a32b204]799 candidates.clear();
800 candidates.splice( candidates.end(), alternatives );
801
802 findMinCost( candidates.begin(), candidates.end(), std::back_inserter( alternatives ) );
[ea83e00a]803
[ca946a4]804 // function may return struct or union value, in which case we need to add alternatives for implicit
805 // conversions to each of the anonymous members, must happen after findMinCost since anon conversions
806 // are never the cheapest expression
807 for ( const Alternative & alt : alternatives ) {
808 addAnonConversions( alt );
809 }
810
[ea83e00a]811 if ( alternatives.empty() && targetType && ! targetType->isVoid() ) {
812 // xxx - this is a temporary hack. If resolution is unsuccessful with a target type, try again without a
813 // target type, since it will sometimes succeed when it wouldn't easily with target type binding. For example,
814 // forall( otype T ) lvalue T ?[?]( T *, ptrdiff_t );
815 // const char * x = "hello world";
816 // unsigned char ch = x[0];
817 // Fails with simple return type binding. First, T is bound to unsigned char, then (x: const char *) is unified
818 // with unsigned char *, which fails because pointer base types must be unified exactly. The new resolver should
819 // fix this issue in a more robust way.
820 targetType = nullptr;
821 visit( untypedExpr );
822 }
[a32b204]823 }
824
825 bool isLvalue( Expression *expr ) {
[906e24d]826 // xxx - recurse into tuples?
[a61ad31]827 return expr->has_result() && ( expr->get_result()->get_lvalue() || dynamic_cast< ReferenceType * >( expr->get_result() ) );
[a32b204]828 }
829
830 void AlternativeFinder::visit( AddressExpr *addressExpr ) {
831 AlternativeFinder finder( indexer, env );
832 finder.find( addressExpr->get_arg() );
833 for ( std::list< Alternative >::iterator i = finder.alternatives.begin(); i != finder.alternatives.end(); ++i ) {
834 if ( isLvalue( i->expr ) ) {
835 alternatives.push_back( Alternative( new AddressExpr( i->expr->clone() ), i->env, i->cost ) );
836 } // if
837 } // for
838 }
839
[62423350]840 Expression * restructureCast( Expression * argExpr, Type * toType ) {
[e6cee92]841 if ( argExpr->get_result()->size() > 1 && ! toType->isVoid() && ! dynamic_cast<ReferenceType *>( toType ) ) {
842 // Argument expression is a tuple and the target type is not void and not a reference type.
843 // Cast each member of the tuple to its corresponding target type, producing the tuple of those
844 // cast expressions. If there are more components of the tuple than components in the target type,
845 // then excess components do not come out in the result expression (but UniqueExprs ensure that
846 // side effects will still be done).
[62423350]847 if ( Tuples::maybeImpure( argExpr ) && ! dynamic_cast< UniqueExpr * >( argExpr ) ) {
848 // expressions which may contain side effects require a single unique instance of the expression.
849 argExpr = new UniqueExpr( argExpr );
850 }
851 std::list< Expression * > componentExprs;
852 for ( unsigned int i = 0; i < toType->size(); i++ ) {
853 // cast each component
854 TupleIndexExpr * idx = new TupleIndexExpr( argExpr->clone(), i );
855 componentExprs.push_back( restructureCast( idx, toType->getComponent( i ) ) );
856 }
857 delete argExpr;
858 assert( componentExprs.size() > 0 );
859 // produce the tuple of casts
860 return new TupleExpr( componentExprs );
861 } else {
862 // handle normally
863 return new CastExpr( argExpr, toType->clone() );
864 }
865 }
866
[a32b204]867 void AlternativeFinder::visit( CastExpr *castExpr ) {
[906e24d]868 Type *& toType = castExpr->get_result();
[7933351]869 assert( toType );
[906e24d]870 toType = resolveTypeof( toType, indexer );
871 SymTab::validateType( toType, &indexer );
872 adjustExprType( toType, env, indexer );
[a32b204]873
874 AlternativeFinder finder( indexer, env );
[7933351]875 finder.targetType = toType;
[a32b204]876 finder.findWithAdjustment( castExpr->get_arg() );
877
878 AltList candidates;
879 for ( std::list< Alternative >::iterator i = finder.alternatives.begin(); i != finder.alternatives.end(); ++i ) {
880 AssertionSet needAssertions, haveAssertions;
881 OpenVarSet openVars;
882
883 // It's possible that a cast can throw away some values in a multiply-valued expression. (An example is a
884 // cast-to-void, which casts from one value to zero.) Figure out the prefix of the subexpression results
885 // that are cast directly. The candidate is invalid if it has fewer results than there are types to cast
886 // to.
[b1bead1]887 int discardedValues = i->expr->get_result()->size() - castExpr->get_result()->size();
[a32b204]888 if ( discardedValues < 0 ) continue;
[7933351]889 // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
890 // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
[adcdd2f]891 // unification run for side-effects
[b1bead1]892 unify( castExpr->get_result(), i->expr->get_result(), i->env, needAssertions, haveAssertions, openVars, indexer );
893 Cost thisCost = castCost( i->expr->get_result(), castExpr->get_result(), indexer, i->env );
[a32b204]894 if ( thisCost != Cost::infinity ) {
895 // count one safe conversion for each value that is thrown away
[89be1c68]896 thisCost.incSafe( discardedValues );
[7933351]897
[62423350]898 candidates.push_back( Alternative( restructureCast( i->expr->clone(), toType ), i->env, i->cost, thisCost ) );
[a32b204]899 } // if
900 } // for
901
902 // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the
903 // cvtCost member to the cost member (since the old cost is now irrelevant). Thus, calling findMinCost twice
904 // selects first based on argument cost, then on conversion cost.
905 AltList minArgCost;
906 findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) );
907 findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );
908 }
909
[a5f0529]910 void AlternativeFinder::visit( VirtualCastExpr * castExpr ) {
911 assertf( castExpr->get_result(), "Implicate virtual cast targets not yet supported." );
912 AlternativeFinder finder( indexer, env );
913 // don't prune here, since it's guaranteed all alternatives will have the same type
914 // (giving the alternatives different types is half of the point of ConstructorExpr nodes)
915 finder.findWithAdjustment( castExpr->get_arg(), false );
916 for ( Alternative & alt : finder.alternatives ) {
917 alternatives.push_back( Alternative(
918 new VirtualCastExpr( alt.expr->clone(), castExpr->get_result()->clone() ),
919 alt.env, alt.cost ) );
920 }
921 }
922
[a32b204]923 void AlternativeFinder::visit( UntypedMemberExpr *memberExpr ) {
924 AlternativeFinder funcFinder( indexer, env );
925 funcFinder.findWithAdjustment( memberExpr->get_aggregate() );
926 for ( AltList::const_iterator agg = funcFinder.alternatives.begin(); agg != funcFinder.alternatives.end(); ++agg ) {
[a61ad31]927 // it's okay for the aggregate expression to have reference type -- cast it to the base type to treat the aggregate as the referenced value
928 std::unique_ptr<Expression> aggrExpr( agg->expr->clone() );
929 Type * aggrType = aggrExpr->get_result();
930 if ( dynamic_cast< ReferenceType * >( aggrType ) ) {
931 aggrType = aggrType->stripReferences();
932 aggrExpr.reset( new CastExpr( aggrExpr.release(), aggrType->clone() ) );
933 }
934 // find member of the given type
935 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) {
936 addAggMembers( structInst, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() );
937 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) {
938 addAggMembers( unionInst, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() );
939 } else if ( TupleType * tupleType = dynamic_cast< TupleType * >( aggrExpr->get_result() ) ) {
940 addTupleMembers( tupleType, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() );
[a32b204]941 } // if
942 } // for
943 }
944
945 void AlternativeFinder::visit( MemberExpr *memberExpr ) {
946 alternatives.push_back( Alternative( memberExpr->clone(), env, Cost::zero ) );
947 }
948
949 void AlternativeFinder::visit( NameExpr *nameExpr ) {
950 std::list< DeclarationWithType* > declList;
951 indexer.lookupId( nameExpr->get_name(), declList );
952 PRINT( std::cerr << "nameExpr is " << nameExpr->get_name() << std::endl; )
[0f19d763]953 for ( std::list< DeclarationWithType* >::iterator i = declList.begin(); i != declList.end(); ++i ) {
954 VariableExpr newExpr( *i, nameExpr->get_argName() );
[89be1c68]955 alternatives.push_back( Alternative( newExpr.clone(), env, Cost::zero ) );
[0f19d763]956 PRINT(
957 std::cerr << "decl is ";
958 (*i)->print( std::cerr );
959 std::cerr << std::endl;
960 std::cerr << "newExpr is ";
961 newExpr.print( std::cerr );
962 std::cerr << std::endl;
[7c64920]963 )
[0f19d763]964 renameTypes( alternatives.back().expr );
[4b0f997]965 addAnonConversions( alternatives.back() ); // add anonymous member interpretations whenever an aggregate value type is seen as a name expression.
[0f19d763]966 } // for
[a32b204]967 }
968
969 void AlternativeFinder::visit( VariableExpr *variableExpr ) {
[85517ddb]970 // not sufficient to clone here, because variable's type may have changed
971 // since the VariableExpr was originally created.
972 alternatives.push_back( Alternative( new VariableExpr( variableExpr->get_var() ), env, Cost::zero ) );
[a32b204]973 }
974
975 void AlternativeFinder::visit( ConstantExpr *constantExpr ) {
976 alternatives.push_back( Alternative( constantExpr->clone(), env, Cost::zero ) );
977 }
978
979 void AlternativeFinder::visit( SizeofExpr *sizeofExpr ) {
980 if ( sizeofExpr->get_isType() ) {
[85517ddb]981 // xxx - resolveTypeof?
[a32b204]982 alternatives.push_back( Alternative( sizeofExpr->clone(), env, Cost::zero ) );
983 } else {
984 // find all alternatives for the argument to sizeof
985 AlternativeFinder finder( indexer, env );
986 finder.find( sizeofExpr->get_expr() );
987 // find the lowest cost alternative among the alternatives, otherwise ambiguous
988 AltList winners;
989 findMinCost( finder.alternatives.begin(), finder.alternatives.end(), back_inserter( winners ) );
990 if ( winners.size() != 1 ) {
991 throw SemanticError( "Ambiguous expression in sizeof operand: ", sizeofExpr->get_expr() );
992 } // if
993 // return the lowest cost alternative for the argument
994 Alternative &choice = winners.front();
[b37dba0]995 referenceToRvalueConversion( choice.expr );
[a32b204]996 alternatives.push_back( Alternative( new SizeofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
[47534159]997 } // if
998 }
999
1000 void AlternativeFinder::visit( AlignofExpr *alignofExpr ) {
1001 if ( alignofExpr->get_isType() ) {
[85517ddb]1002 // xxx - resolveTypeof?
[47534159]1003 alternatives.push_back( Alternative( alignofExpr->clone(), env, Cost::zero ) );
1004 } else {
1005 // find all alternatives for the argument to sizeof
1006 AlternativeFinder finder( indexer, env );
1007 finder.find( alignofExpr->get_expr() );
1008 // find the lowest cost alternative among the alternatives, otherwise ambiguous
1009 AltList winners;
1010 findMinCost( finder.alternatives.begin(), finder.alternatives.end(), back_inserter( winners ) );
1011 if ( winners.size() != 1 ) {
1012 throw SemanticError( "Ambiguous expression in alignof operand: ", alignofExpr->get_expr() );
1013 } // if
1014 // return the lowest cost alternative for the argument
1015 Alternative &choice = winners.front();
[b37dba0]1016 referenceToRvalueConversion( choice.expr );
[47534159]1017 alternatives.push_back( Alternative( new AlignofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
[a32b204]1018 } // if
1019 }
1020
[2a4b088]1021 template< typename StructOrUnionType >
1022 void AlternativeFinder::addOffsetof( StructOrUnionType *aggInst, const std::string &name ) {
1023 std::list< Declaration* > members;
1024 aggInst->lookup( name, members );
1025 for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) {
1026 if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) {
[79970ed]1027 alternatives.push_back( Alternative( new OffsetofExpr( aggInst->clone(), dwt ), env, Cost::zero ) );
[2a4b088]1028 renameTypes( alternatives.back().expr );
1029 } else {
1030 assert( false );
1031 }
1032 }
1033 }
[6ed1d4b]1034
[2a4b088]1035 void AlternativeFinder::visit( UntypedOffsetofExpr *offsetofExpr ) {
1036 AlternativeFinder funcFinder( indexer, env );
[85517ddb]1037 // xxx - resolveTypeof?
[2a4b088]1038 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( offsetofExpr->get_type() ) ) {
1039 addOffsetof( structInst, offsetofExpr->get_member() );
1040 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( offsetofExpr->get_type() ) ) {
1041 addOffsetof( unionInst, offsetofExpr->get_member() );
1042 }
1043 }
[6ed1d4b]1044
[25a054f]1045 void AlternativeFinder::visit( OffsetofExpr *offsetofExpr ) {
1046 alternatives.push_back( Alternative( offsetofExpr->clone(), env, Cost::zero ) );
[afc1045]1047 }
1048
1049 void AlternativeFinder::visit( OffsetPackExpr *offsetPackExpr ) {
1050 alternatives.push_back( Alternative( offsetPackExpr->clone(), env, Cost::zero ) );
[25a054f]1051 }
1052
[a32b204]1053 void AlternativeFinder::resolveAttr( DeclarationWithType *funcDecl, FunctionType *function, Type *argType, const TypeEnvironment &env ) {
1054 // assume no polymorphism
1055 // assume no implicit conversions
1056 assert( function->get_parameters().size() == 1 );
1057 PRINT(
[6ed1d4b]1058 std::cerr << "resolvAttr: funcDecl is ";
1059 funcDecl->print( std::cerr );
1060 std::cerr << " argType is ";
1061 argType->print( std::cerr );
1062 std::cerr << std::endl;
[7c64920]1063 )
1064 if ( typesCompatibleIgnoreQualifiers( argType, function->get_parameters().front()->get_type(), indexer, env ) ) {
1065 alternatives.push_back( Alternative( new AttrExpr( new VariableExpr( funcDecl ), argType->clone() ), env, Cost::zero ) );
1066 for ( std::list< DeclarationWithType* >::iterator i = function->get_returnVals().begin(); i != function->get_returnVals().end(); ++i ) {
[906e24d]1067 alternatives.back().expr->set_result( (*i)->get_type()->clone() );
[7c64920]1068 } // for
1069 } // if
[a32b204]1070 }
1071
1072 void AlternativeFinder::visit( AttrExpr *attrExpr ) {
1073 // assume no 'pointer-to-attribute'
1074 NameExpr *nameExpr = dynamic_cast< NameExpr* >( attrExpr->get_attr() );
1075 assert( nameExpr );
1076 std::list< DeclarationWithType* > attrList;
1077 indexer.lookupId( nameExpr->get_name(), attrList );
1078 if ( attrExpr->get_isType() || attrExpr->get_expr() ) {
1079 for ( std::list< DeclarationWithType* >::iterator i = attrList.begin(); i != attrList.end(); ++i ) {
1080 // check if the type is function
1081 if ( FunctionType *function = dynamic_cast< FunctionType* >( (*i)->get_type() ) ) {
1082 // assume exactly one parameter
1083 if ( function->get_parameters().size() == 1 ) {
1084 if ( attrExpr->get_isType() ) {
1085 resolveAttr( *i, function, attrExpr->get_type(), env );
1086 } else {
1087 AlternativeFinder finder( indexer, env );
1088 finder.find( attrExpr->get_expr() );
1089 for ( AltList::iterator choice = finder.alternatives.begin(); choice != finder.alternatives.end(); ++choice ) {
[906e24d]1090 if ( choice->expr->get_result()->size() == 1 ) {
1091 resolveAttr(*i, function, choice->expr->get_result(), choice->env );
[a32b204]1092 } // fi
1093 } // for
1094 } // if
1095 } // if
1096 } // if
1097 } // for
1098 } else {
1099 for ( std::list< DeclarationWithType* >::iterator i = attrList.begin(); i != attrList.end(); ++i ) {
1100 VariableExpr newExpr( *i );
[89be1c68]1101 alternatives.push_back( Alternative( newExpr.clone(), env, Cost::zero ) );
[a32b204]1102 renameTypes( alternatives.back().expr );
1103 } // for
1104 } // if
1105 }
1106
1107 void AlternativeFinder::visit( LogicalExpr *logicalExpr ) {
1108 AlternativeFinder firstFinder( indexer, env );
1109 firstFinder.findWithAdjustment( logicalExpr->get_arg1() );
1110 for ( AltList::const_iterator first = firstFinder.alternatives.begin(); first != firstFinder.alternatives.end(); ++first ) {
1111 AlternativeFinder secondFinder( indexer, first->env );
1112 secondFinder.findWithAdjustment( logicalExpr->get_arg2() );
1113 for ( AltList::const_iterator second = secondFinder.alternatives.begin(); second != secondFinder.alternatives.end(); ++second ) {
1114 LogicalExpr *newExpr = new LogicalExpr( first->expr->clone(), second->expr->clone(), logicalExpr->get_isAnd() );
1115 alternatives.push_back( Alternative( newExpr, second->env, first->cost + second->cost ) );
[d9a0e76]1116 }
1117 }
1118 }
[51b73452]1119
[a32b204]1120 void AlternativeFinder::visit( ConditionalExpr *conditionalExpr ) {
[32b8144]1121 // find alternatives for condition
[a32b204]1122 AlternativeFinder firstFinder( indexer, env );
1123 firstFinder.findWithAdjustment( conditionalExpr->get_arg1() );
1124 for ( AltList::const_iterator first = firstFinder.alternatives.begin(); first != firstFinder.alternatives.end(); ++first ) {
[32b8144]1125 // find alternatives for true expression
[a32b204]1126 AlternativeFinder secondFinder( indexer, first->env );
1127 secondFinder.findWithAdjustment( conditionalExpr->get_arg2() );
1128 for ( AltList::const_iterator second = secondFinder.alternatives.begin(); second != secondFinder.alternatives.end(); ++second ) {
[32b8144]1129 // find alterantives for false expression
[a32b204]1130 AlternativeFinder thirdFinder( indexer, second->env );
1131 thirdFinder.findWithAdjustment( conditionalExpr->get_arg3() );
1132 for ( AltList::const_iterator third = thirdFinder.alternatives.begin(); third != thirdFinder.alternatives.end(); ++third ) {
[32b8144]1133 // unify true and false types, then infer parameters to produce new alternatives
[a32b204]1134 OpenVarSet openVars;
1135 AssertionSet needAssertions, haveAssertions;
1136 Alternative newAlt( 0, third->env, first->cost + second->cost + third->cost );
[668e971a]1137 Type* commonType = nullptr;
[906e24d]1138 if ( unify( second->expr->get_result(), third->expr->get_result(), newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
[a32b204]1139 ConditionalExpr *newExpr = new ConditionalExpr( first->expr->clone(), second->expr->clone(), third->expr->clone() );
[906e24d]1140 newExpr->set_result( commonType ? commonType : second->expr->get_result()->clone() );
[a32b204]1141 newAlt.expr = newExpr;
1142 inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
1143 } // if
1144 } // for
1145 } // for
1146 } // for
1147 }
1148
1149 void AlternativeFinder::visit( CommaExpr *commaExpr ) {
1150 TypeEnvironment newEnv( env );
1151 Expression *newFirstArg = resolveInVoidContext( commaExpr->get_arg1(), indexer, newEnv );
1152 AlternativeFinder secondFinder( indexer, newEnv );
1153 secondFinder.findWithAdjustment( commaExpr->get_arg2() );
1154 for ( AltList::const_iterator alt = secondFinder.alternatives.begin(); alt != secondFinder.alternatives.end(); ++alt ) {
1155 alternatives.push_back( Alternative( new CommaExpr( newFirstArg->clone(), alt->expr->clone() ), alt->env, alt->cost ) );
1156 } // for
1157 delete newFirstArg;
1158 }
1159
[32b8144]1160 void AlternativeFinder::visit( RangeExpr * rangeExpr ) {
1161 // resolve low and high, accept alternatives whose low and high types unify
1162 AlternativeFinder firstFinder( indexer, env );
1163 firstFinder.findWithAdjustment( rangeExpr->get_low() );
1164 for ( AltList::const_iterator first = firstFinder.alternatives.begin(); first != firstFinder.alternatives.end(); ++first ) {
1165 AlternativeFinder secondFinder( indexer, first->env );
1166 secondFinder.findWithAdjustment( rangeExpr->get_high() );
1167 for ( AltList::const_iterator second = secondFinder.alternatives.begin(); second != secondFinder.alternatives.end(); ++second ) {
1168 OpenVarSet openVars;
1169 AssertionSet needAssertions, haveAssertions;
1170 Alternative newAlt( 0, second->env, first->cost + second->cost );
1171 Type* commonType = nullptr;
1172 if ( unify( first->expr->get_result(), second->expr->get_result(), newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
1173 RangeExpr *newExpr = new RangeExpr( first->expr->clone(), second->expr->clone() );
1174 newExpr->set_result( commonType ? commonType : first->expr->get_result()->clone() );
1175 newAlt.expr = newExpr;
1176 inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
1177 } // if
1178 } // for
1179 } // for
1180 }
1181
[907eccb]1182 void AlternativeFinder::visit( UntypedTupleExpr *tupleExpr ) {
[a32b204]1183 std::list< AlternativeFinder > subExprAlternatives;
1184 findSubExprs( tupleExpr->get_exprs().begin(), tupleExpr->get_exprs().end(), back_inserter( subExprAlternatives ) );
1185 std::list< AltList > possibilities;
1186 combos( subExprAlternatives.begin(), subExprAlternatives.end(), back_inserter( possibilities ) );
1187 for ( std::list< AltList >::const_iterator i = possibilities.begin(); i != possibilities.end(); ++i ) {
[907eccb]1188 std::list< Expression * > exprs;
1189 makeExprList( *i, exprs );
[a32b204]1190
1191 TypeEnvironment compositeEnv;
1192 simpleCombineEnvironments( i->begin(), i->end(), compositeEnv );
[907eccb]1193 alternatives.push_back( Alternative( new TupleExpr( exprs ) , compositeEnv, sumCost( *i ) ) );
[a32b204]1194 } // for
[d9a0e76]1195 }
[dc2e7e0]1196
[907eccb]1197 void AlternativeFinder::visit( TupleExpr *tupleExpr ) {
1198 alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
1199 }
1200
[dc2e7e0]1201 void AlternativeFinder::visit( ImplicitCopyCtorExpr * impCpCtorExpr ) {
1202 alternatives.push_back( Alternative( impCpCtorExpr->clone(), env, Cost::zero ) );
1203 }
[b6fe7e6]1204
1205 void AlternativeFinder::visit( ConstructorExpr * ctorExpr ) {
1206 AlternativeFinder finder( indexer, env );
1207 // don't prune here, since it's guaranteed all alternatives will have the same type
1208 // (giving the alternatives different types is half of the point of ConstructorExpr nodes)
1209 finder.findWithAdjustment( ctorExpr->get_callExpr(), false );
1210 for ( Alternative & alt : finder.alternatives ) {
1211 alternatives.push_back( Alternative( new ConstructorExpr( alt.expr->clone() ), alt.env, alt.cost ) );
1212 }
1213 }
[8f7cea1]1214
1215 void AlternativeFinder::visit( TupleIndexExpr *tupleExpr ) {
1216 alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
1217 }
[aa8f9df]1218
1219 void AlternativeFinder::visit( TupleAssignExpr *tupleAssignExpr ) {
1220 alternatives.push_back( Alternative( tupleAssignExpr->clone(), env, Cost::zero ) );
1221 }
[bf32bb8]1222
1223 void AlternativeFinder::visit( UniqueExpr *unqExpr ) {
1224 AlternativeFinder finder( indexer, env );
1225 finder.findWithAdjustment( unqExpr->get_expr() );
1226 for ( Alternative & alt : finder.alternatives ) {
[141b786]1227 // ensure that the id is passed on to the UniqueExpr alternative so that the expressions are "linked"
[77971f6]1228 UniqueExpr * newUnqExpr = new UniqueExpr( alt.expr->clone(), unqExpr->get_id() );
[141b786]1229 alternatives.push_back( Alternative( newUnqExpr, alt.env, alt.cost ) );
[bf32bb8]1230 }
1231 }
1232
[722617d]1233 void AlternativeFinder::visit( StmtExpr *stmtExpr ) {
1234 StmtExpr * newStmtExpr = stmtExpr->clone();
1235 ResolvExpr::resolveStmtExpr( newStmtExpr, indexer );
1236 // xxx - this env is almost certainly wrong, and needs to somehow contain the combined environments from all of the statements in the stmtExpr...
1237 alternatives.push_back( Alternative( newStmtExpr, env, Cost::zero ) );
1238 }
1239
[e4d829b]1240 void AlternativeFinder::visit( UntypedInitExpr *initExpr ) {
[62423350]1241 // handle each option like a cast
[e4d829b]1242 AltList candidates;
[62423350]1243 PRINT( std::cerr << "untyped init expr: " << initExpr << std::endl; )
[e4d829b]1244 // O(N^2) checks of d-types with e-types
[62423350]1245 for ( InitAlternative & initAlt : initExpr->get_initAlts() ) {
1246 Type * toType = resolveTypeof( initAlt.type, indexer );
1247 SymTab::validateType( toType, &indexer );
1248 adjustExprType( toType, env, indexer );
1249 // Ideally the call to findWithAdjustment could be moved out of the loop, but unfortunately it currently has to occur inside or else
1250 // polymorphic return types are not properly bound to the initialization type, since return type variables are only open for the duration of resolving
1251 // the UntypedExpr. This is only actually an issue in initialization contexts that allow more than one possible initialization type, but it is still suboptimal.
1252 AlternativeFinder finder( indexer, env );
1253 finder.targetType = toType;
1254 finder.findWithAdjustment( initExpr->get_expr() );
1255 for ( Alternative & alt : finder.get_alternatives() ) {
1256 TypeEnvironment newEnv( alt.env );
[e4d829b]1257 AssertionSet needAssertions, haveAssertions;
[62423350]1258 OpenVarSet openVars; // find things in env that don't have a "representative type" and claim those are open vars?
1259 PRINT( std::cerr << " @ " << toType << " " << initAlt.designation << std::endl; )
[e4d829b]1260 // It's possible that a cast can throw away some values in a multiply-valued expression. (An example is a
1261 // cast-to-void, which casts from one value to zero.) Figure out the prefix of the subexpression results
1262 // that are cast directly. The candidate is invalid if it has fewer results than there are types to cast
1263 // to.
[62423350]1264 int discardedValues = alt.expr->get_result()->size() - toType->size();
[e4d829b]1265 if ( discardedValues < 0 ) continue;
1266 // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
1267 // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
1268 // unification run for side-effects
[62423350]1269 unify( toType, alt.expr->get_result(), newEnv, needAssertions, haveAssertions, openVars, indexer ); // xxx - do some inspecting on this line... why isn't result bound to initAlt.type??
[e4d829b]1270
[62423350]1271 Cost thisCost = castCost( alt.expr->get_result(), toType, indexer, newEnv );
[e4d829b]1272 if ( thisCost != Cost::infinity ) {
1273 // count one safe conversion for each value that is thrown away
[89be1c68]1274 thisCost.incSafe( discardedValues );
[62423350]1275 candidates.push_back( Alternative( new InitExpr( restructureCast( alt.expr->clone(), toType ), initAlt.designation->clone() ), newEnv, alt.cost, thisCost ) );
[e4d829b]1276 }
1277 }
1278 }
1279
1280 // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the
1281 // cvtCost member to the cost member (since the old cost is now irrelevant). Thus, calling findMinCost twice
1282 // selects first based on argument cost, then on conversion cost.
1283 AltList minArgCost;
1284 findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) );
1285 findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );
1286 }
[51b73452]1287} // namespace ResolvExpr
[a32b204]1288
1289// Local Variables: //
1290// tab-width: 4 //
1291// mode: c++ //
1292// compile-command: "make install" //
1293// End: //
Note: See TracBrowser for help on using the repository browser.