source: src/ResolvExpr/AlternativeFinder.cc@ 1cb758f2

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 1cb758f2 was 6ccfb7f, checked in by Rob Schluntz <rschlunt@…>, 8 years ago

Unconditionally attempt to resolve function operators with function alternative [fixes #23]

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