source: src/ResolvExpr/AlternativeFinder.cc@ bf7b9da7

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 bf7b9da7 was ddf8a29, checked in by Rob Schluntz <rschlunt@…>, 8 years ago

Refactor computeConversionCost, apply conversions to ConditionalExpr arguments, re-add Werror to libcfa build

  • 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 bool doneInit = false;
701 AlternativeFinder funcOpFinder( indexer, env );
702
703 AlternativeFinder funcFinder( indexer, env );
704
705 {
706 std::string fname = InitTweak::getFunctionName( untypedExpr );
707 if ( fname == "&&" ) {
708 VoidType v = Type::Qualifiers(); // resolve to type void *
709 PointerType pt( Type::Qualifiers(), v.clone() );
710 UntypedExpr *vexpr = untypedExpr->clone();
711 vexpr->set_result( pt.clone() );
712 alternatives.push_back( Alternative( vexpr, env, Cost::zero) );
713 return;
714 }
715 }
716
717 funcFinder.findWithAdjustment( untypedExpr->get_function() );
718 std::list< AlternativeFinder > argAlternatives;
719 findSubExprs( untypedExpr->begin_args(), untypedExpr->end_args(), back_inserter( argAlternatives ) );
720
721 std::list< AltList > possibilities;
722 combos( argAlternatives.begin(), argAlternatives.end(), back_inserter( possibilities ) );
723
724 // take care of possible tuple assignments
725 // if not tuple assignment, assignment is taken care of as a normal function call
726 Tuples::handleTupleAssignment( *this, untypedExpr, possibilities );
727
728 AltList candidates;
729 SemanticError errors;
730 for ( AltList::iterator func = funcFinder.alternatives.begin(); func != funcFinder.alternatives.end(); ++func ) {
731 try {
732 PRINT(
733 std::cerr << "working on alternative: " << std::endl;
734 func->print( std::cerr, 8 );
735 )
736 // check if the type is pointer to function
737 if ( PointerType *pointer = dynamic_cast< PointerType* >( func->expr->get_result()->stripReferences() ) ) {
738 if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() ) ) {
739 referenceToRvalueConversion( func->expr );
740 for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) {
741 // XXX
742 //Designators::check_alternative( function, *actualAlt );
743 makeFunctionAlternatives( *func, function, *actualAlt, std::back_inserter( candidates ) );
744 }
745 }
746 } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr->get_result()->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer)
747 referenceToRvalueConversion( func->expr );
748 EqvClass eqvClass;
749 if ( func->env.lookup( typeInst->get_name(), eqvClass ) && eqvClass.type ) {
750 if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass.type ) ) {
751 for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) {
752 makeFunctionAlternatives( *func, function, *actualAlt, std::back_inserter( candidates ) );
753 } // for
754 } // if
755 } // if
756 } else {
757 // seek a function operator that's compatible
758 if ( ! doneInit ) {
759 doneInit = true;
760 NameExpr *opExpr = new NameExpr( "?()" );
761 try {
762 funcOpFinder.findWithAdjustment( opExpr );
763 } catch( SemanticError &e ) {
764 // it's ok if there aren't any defined function ops
765 }
766 PRINT(
767 std::cerr << "known function ops:" << std::endl;
768 printAlts( funcOpFinder.alternatives, std::cerr, 8 );
769 )
770 }
771
772 for ( AltList::iterator funcOp = funcOpFinder.alternatives.begin(); funcOp != funcOpFinder.alternatives.end(); ++funcOp ) {
773 // check if the type is pointer to function
774 if ( PointerType *pointer = dynamic_cast< PointerType* >( funcOp->expr->get_result()->stripReferences() ) ) {
775 if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() ) ) {
776 referenceToRvalueConversion( funcOp->expr );
777 for ( std::list< AltList >::iterator actualAlt = possibilities.begin(); actualAlt != possibilities.end(); ++actualAlt ) {
778 AltList currentAlt;
779 currentAlt.push_back( *func );
780 currentAlt.insert( currentAlt.end(), actualAlt->begin(), actualAlt->end() );
781 makeFunctionAlternatives( *funcOp, function, currentAlt, std::back_inserter( candidates ) );
782 } // for
783 } // if
784 } // if
785 } // for
786 } // if
787 } catch ( SemanticError &e ) {
788 errors.append( e );
789 }
790 } // for
791
792 // Implement SFINAE; resolution errors are only errors if there aren't any non-erroneous resolutions
793 if ( candidates.empty() && ! errors.isEmpty() ) { throw errors; }
794
795 // compute conversionsion costs
796 for ( AltList::iterator withFunc = candidates.begin(); withFunc != candidates.end(); ++withFunc ) {
797 Cost cvtCost = computeApplicationConversionCost( *withFunc, indexer );
798
799 PRINT(
800 ApplicationExpr *appExpr = safe_dynamic_cast< ApplicationExpr* >( withFunc->expr );
801 PointerType *pointer = safe_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
802 FunctionType *function = safe_dynamic_cast< FunctionType* >( pointer->get_base() );
803 std::cerr << "Case +++++++++++++ " << appExpr->get_function() << std::endl;
804 std::cerr << "formals are:" << std::endl;
805 printAll( function->get_parameters(), std::cerr, 8 );
806 std::cerr << "actuals are:" << std::endl;
807 printAll( appExpr->get_args(), std::cerr, 8 );
808 std::cerr << "bindings are:" << std::endl;
809 withFunc->env.print( std::cerr, 8 );
810 std::cerr << "cost of conversion is:" << cvtCost << std::endl;
811 )
812 if ( cvtCost != Cost::infinity ) {
813 withFunc->cvtCost = cvtCost;
814 alternatives.push_back( *withFunc );
815 } // if
816 } // for
817
818 candidates.clear();
819 candidates.splice( candidates.end(), alternatives );
820
821 findMinCost( candidates.begin(), candidates.end(), std::back_inserter( alternatives ) );
822
823 // function may return struct or union value, in which case we need to add alternatives for implicit
824 // conversions to each of the anonymous members, must happen after findMinCost since anon conversions
825 // are never the cheapest expression
826 for ( const Alternative & alt : alternatives ) {
827 addAnonConversions( alt );
828 }
829
830 if ( alternatives.empty() && targetType && ! targetType->isVoid() ) {
831 // xxx - this is a temporary hack. If resolution is unsuccessful with a target type, try again without a
832 // target type, since it will sometimes succeed when it wouldn't easily with target type binding. For example,
833 // forall( otype T ) lvalue T ?[?]( T *, ptrdiff_t );
834 // const char * x = "hello world";
835 // unsigned char ch = x[0];
836 // Fails with simple return type binding. First, T is bound to unsigned char, then (x: const char *) is unified
837 // with unsigned char *, which fails because pointer base types must be unified exactly. The new resolver should
838 // fix this issue in a more robust way.
839 targetType = nullptr;
840 visit( untypedExpr );
841 }
842 }
843
844 bool isLvalue( Expression *expr ) {
845 // xxx - recurse into tuples?
846 return expr->has_result() && ( expr->get_result()->get_lvalue() || dynamic_cast< ReferenceType * >( expr->get_result() ) );
847 }
848
849 void AlternativeFinder::visit( AddressExpr *addressExpr ) {
850 AlternativeFinder finder( indexer, env );
851 finder.find( addressExpr->get_arg() );
852 for ( std::list< Alternative >::iterator i = finder.alternatives.begin(); i != finder.alternatives.end(); ++i ) {
853 if ( isLvalue( i->expr ) ) {
854 alternatives.push_back( Alternative( new AddressExpr( i->expr->clone() ), i->env, i->cost ) );
855 } // if
856 } // for
857 }
858
859 Expression * restructureCast( Expression * argExpr, Type * toType ) {
860 if ( argExpr->get_result()->size() > 1 && ! toType->isVoid() && ! dynamic_cast<ReferenceType *>( toType ) ) {
861 // Argument expression is a tuple and the target type is not void and not a reference type.
862 // Cast each member of the tuple to its corresponding target type, producing the tuple of those
863 // cast expressions. If there are more components of the tuple than components in the target type,
864 // then excess components do not come out in the result expression (but UniqueExprs ensure that
865 // side effects will still be done).
866 if ( Tuples::maybeImpureIgnoreUnique( argExpr ) ) {
867 // expressions which may contain side effects require a single unique instance of the expression.
868 argExpr = new UniqueExpr( argExpr );
869 }
870 std::list< Expression * > componentExprs;
871 for ( unsigned int i = 0; i < toType->size(); i++ ) {
872 // cast each component
873 TupleIndexExpr * idx = new TupleIndexExpr( argExpr->clone(), i );
874 componentExprs.push_back( restructureCast( idx, toType->getComponent( i ) ) );
875 }
876 delete argExpr;
877 assert( componentExprs.size() > 0 );
878 // produce the tuple of casts
879 return new TupleExpr( componentExprs );
880 } else {
881 // handle normally
882 return new CastExpr( argExpr, toType->clone() );
883 }
884 }
885
886 void AlternativeFinder::visit( CastExpr *castExpr ) {
887 Type *& toType = castExpr->get_result();
888 assert( toType );
889 toType = resolveTypeof( toType, indexer );
890 SymTab::validateType( toType, &indexer );
891 adjustExprType( toType, env, indexer );
892
893 AlternativeFinder finder( indexer, env );
894 finder.targetType = toType;
895 finder.findWithAdjustment( castExpr->get_arg() );
896
897 AltList candidates;
898 for ( std::list< Alternative >::iterator i = finder.alternatives.begin(); i != finder.alternatives.end(); ++i ) {
899 AssertionSet needAssertions, haveAssertions;
900 OpenVarSet openVars;
901
902 // It's possible that a cast can throw away some values in a multiply-valued expression. (An example is a
903 // cast-to-void, which casts from one value to zero.) Figure out the prefix of the subexpression results
904 // that are cast directly. The candidate is invalid if it has fewer results than there are types to cast
905 // to.
906 int discardedValues = i->expr->get_result()->size() - castExpr->get_result()->size();
907 if ( discardedValues < 0 ) continue;
908 // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
909 // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
910 // unification run for side-effects
911 unify( castExpr->get_result(), i->expr->get_result(), i->env, needAssertions, haveAssertions, openVars, indexer );
912 Cost thisCost = castCost( i->expr->get_result(), castExpr->get_result(), indexer, i->env );
913 if ( thisCost != Cost::infinity ) {
914 // count one safe conversion for each value that is thrown away
915 thisCost.incSafe( discardedValues );
916 Alternative newAlt( restructureCast( i->expr->clone(), toType ), i->env, i->cost, thisCost );
917 // xxx - this doesn't work at the moment, since inferParameters requires an ApplicationExpr as the alternative.
918 // Once this works, it should be possible to infer parameters on a cast expression and specialize any function.
919
920 // inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( candidates ) );
921 candidates.emplace_back( std::move( newAlt ) );
922 } // if
923 } // for
924
925 // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the
926 // cvtCost member to the cost member (since the old cost is now irrelevant). Thus, calling findMinCost twice
927 // selects first based on argument cost, then on conversion cost.
928 AltList minArgCost;
929 findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) );
930 findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );
931 }
932
933 void AlternativeFinder::visit( VirtualCastExpr * castExpr ) {
934 assertf( castExpr->get_result(), "Implicate virtual cast targets not yet supported." );
935 AlternativeFinder finder( indexer, env );
936 // don't prune here, since it's guaranteed all alternatives will have the same type
937 // (giving the alternatives different types is half of the point of ConstructorExpr nodes)
938 finder.findWithAdjustment( castExpr->get_arg(), false );
939 for ( Alternative & alt : finder.alternatives ) {
940 alternatives.push_back( Alternative(
941 new VirtualCastExpr( alt.expr->clone(), castExpr->get_result()->clone() ),
942 alt.env, alt.cost ) );
943 }
944 }
945
946 void AlternativeFinder::visit( UntypedMemberExpr *memberExpr ) {
947 AlternativeFinder funcFinder( indexer, env );
948 funcFinder.findWithAdjustment( memberExpr->get_aggregate() );
949 for ( AltList::const_iterator agg = funcFinder.alternatives.begin(); agg != funcFinder.alternatives.end(); ++agg ) {
950 // 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
951 std::unique_ptr<Expression> aggrExpr( agg->expr->clone() );
952 Type * aggrType = aggrExpr->get_result();
953 if ( dynamic_cast< ReferenceType * >( aggrType ) ) {
954 aggrType = aggrType->stripReferences();
955 aggrExpr.reset( new CastExpr( aggrExpr.release(), aggrType->clone() ) );
956 }
957 // find member of the given type
958 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) {
959 addAggMembers( structInst, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() );
960 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) {
961 addAggMembers( unionInst, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() );
962 } else if ( TupleType * tupleType = dynamic_cast< TupleType * >( aggrExpr->get_result() ) ) {
963 addTupleMembers( tupleType, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() );
964 } // if
965 } // for
966 }
967
968 void AlternativeFinder::visit( MemberExpr *memberExpr ) {
969 alternatives.push_back( Alternative( memberExpr->clone(), env, Cost::zero ) );
970 }
971
972 void AlternativeFinder::visit( NameExpr *nameExpr ) {
973 std::list< DeclarationWithType* > declList;
974 indexer.lookupId( nameExpr->get_name(), declList );
975 PRINT( std::cerr << "nameExpr is " << nameExpr->get_name() << std::endl; )
976 for ( std::list< DeclarationWithType* >::iterator i = declList.begin(); i != declList.end(); ++i ) {
977 VariableExpr newExpr( *i, nameExpr->get_argName() );
978 alternatives.push_back( Alternative( newExpr.clone(), env, Cost::zero ) );
979 PRINT(
980 std::cerr << "decl is ";
981 (*i)->print( std::cerr );
982 std::cerr << std::endl;
983 std::cerr << "newExpr is ";
984 newExpr.print( std::cerr );
985 std::cerr << std::endl;
986 )
987 renameTypes( alternatives.back().expr );
988 addAnonConversions( alternatives.back() ); // add anonymous member interpretations whenever an aggregate value type is seen as a name expression.
989 } // for
990 }
991
992 void AlternativeFinder::visit( VariableExpr *variableExpr ) {
993 // not sufficient to clone here, because variable's type may have changed
994 // since the VariableExpr was originally created.
995 alternatives.push_back( Alternative( new VariableExpr( variableExpr->get_var() ), env, Cost::zero ) );
996 }
997
998 void AlternativeFinder::visit( ConstantExpr *constantExpr ) {
999 alternatives.push_back( Alternative( constantExpr->clone(), env, Cost::zero ) );
1000 }
1001
1002 void AlternativeFinder::visit( SizeofExpr *sizeofExpr ) {
1003 if ( sizeofExpr->get_isType() ) {
1004 Type * newType = sizeofExpr->get_type()->clone();
1005 alternatives.push_back( Alternative( new SizeofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
1006 } else {
1007 // find all alternatives for the argument to sizeof
1008 AlternativeFinder finder( indexer, env );
1009 finder.find( sizeofExpr->get_expr() );
1010 // find the lowest cost alternative among the alternatives, otherwise ambiguous
1011 AltList winners;
1012 findMinCost( finder.alternatives.begin(), finder.alternatives.end(), back_inserter( winners ) );
1013 if ( winners.size() != 1 ) {
1014 throw SemanticError( "Ambiguous expression in sizeof operand: ", sizeofExpr->get_expr() );
1015 } // if
1016 // return the lowest cost alternative for the argument
1017 Alternative &choice = winners.front();
1018 referenceToRvalueConversion( choice.expr );
1019 alternatives.push_back( Alternative( new SizeofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
1020 } // if
1021 }
1022
1023 void AlternativeFinder::visit( AlignofExpr *alignofExpr ) {
1024 if ( alignofExpr->get_isType() ) {
1025 Type * newType = alignofExpr->get_type()->clone();
1026 alternatives.push_back( Alternative( new AlignofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
1027 } else {
1028 // find all alternatives for the argument to sizeof
1029 AlternativeFinder finder( indexer, env );
1030 finder.find( alignofExpr->get_expr() );
1031 // find the lowest cost alternative among the alternatives, otherwise ambiguous
1032 AltList winners;
1033 findMinCost( finder.alternatives.begin(), finder.alternatives.end(), back_inserter( winners ) );
1034 if ( winners.size() != 1 ) {
1035 throw SemanticError( "Ambiguous expression in alignof operand: ", alignofExpr->get_expr() );
1036 } // if
1037 // return the lowest cost alternative for the argument
1038 Alternative &choice = winners.front();
1039 referenceToRvalueConversion( choice.expr );
1040 alternatives.push_back( Alternative( new AlignofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
1041 } // if
1042 }
1043
1044 template< typename StructOrUnionType >
1045 void AlternativeFinder::addOffsetof( StructOrUnionType *aggInst, const std::string &name ) {
1046 std::list< Declaration* > members;
1047 aggInst->lookup( name, members );
1048 for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) {
1049 if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) {
1050 alternatives.push_back( Alternative( new OffsetofExpr( aggInst->clone(), dwt ), env, Cost::zero ) );
1051 renameTypes( alternatives.back().expr );
1052 } else {
1053 assert( false );
1054 }
1055 }
1056 }
1057
1058 void AlternativeFinder::visit( UntypedOffsetofExpr *offsetofExpr ) {
1059 AlternativeFinder funcFinder( indexer, env );
1060 // xxx - resolveTypeof?
1061 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( offsetofExpr->get_type() ) ) {
1062 addOffsetof( structInst, offsetofExpr->get_member() );
1063 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( offsetofExpr->get_type() ) ) {
1064 addOffsetof( unionInst, offsetofExpr->get_member() );
1065 }
1066 }
1067
1068 void AlternativeFinder::visit( OffsetofExpr *offsetofExpr ) {
1069 alternatives.push_back( Alternative( offsetofExpr->clone(), env, Cost::zero ) );
1070 }
1071
1072 void AlternativeFinder::visit( OffsetPackExpr *offsetPackExpr ) {
1073 alternatives.push_back( Alternative( offsetPackExpr->clone(), env, Cost::zero ) );
1074 }
1075
1076 void AlternativeFinder::resolveAttr( DeclarationWithType *funcDecl, FunctionType *function, Type *argType, const TypeEnvironment &env ) {
1077 // assume no polymorphism
1078 // assume no implicit conversions
1079 assert( function->get_parameters().size() == 1 );
1080 PRINT(
1081 std::cerr << "resolvAttr: funcDecl is ";
1082 funcDecl->print( std::cerr );
1083 std::cerr << " argType is ";
1084 argType->print( std::cerr );
1085 std::cerr << std::endl;
1086 )
1087 if ( typesCompatibleIgnoreQualifiers( argType, function->get_parameters().front()->get_type(), indexer, env ) ) {
1088 alternatives.push_back( Alternative( new AttrExpr( new VariableExpr( funcDecl ), argType->clone() ), env, Cost::zero ) );
1089 for ( std::list< DeclarationWithType* >::iterator i = function->get_returnVals().begin(); i != function->get_returnVals().end(); ++i ) {
1090 alternatives.back().expr->set_result( (*i)->get_type()->clone() );
1091 } // for
1092 } // if
1093 }
1094
1095 void AlternativeFinder::visit( AttrExpr *attrExpr ) {
1096 // assume no 'pointer-to-attribute'
1097 NameExpr *nameExpr = dynamic_cast< NameExpr* >( attrExpr->get_attr() );
1098 assert( nameExpr );
1099 std::list< DeclarationWithType* > attrList;
1100 indexer.lookupId( nameExpr->get_name(), attrList );
1101 if ( attrExpr->get_isType() || attrExpr->get_expr() ) {
1102 for ( std::list< DeclarationWithType* >::iterator i = attrList.begin(); i != attrList.end(); ++i ) {
1103 // check if the type is function
1104 if ( FunctionType *function = dynamic_cast< FunctionType* >( (*i)->get_type() ) ) {
1105 // assume exactly one parameter
1106 if ( function->get_parameters().size() == 1 ) {
1107 if ( attrExpr->get_isType() ) {
1108 resolveAttr( *i, function, attrExpr->get_type(), env );
1109 } else {
1110 AlternativeFinder finder( indexer, env );
1111 finder.find( attrExpr->get_expr() );
1112 for ( AltList::iterator choice = finder.alternatives.begin(); choice != finder.alternatives.end(); ++choice ) {
1113 if ( choice->expr->get_result()->size() == 1 ) {
1114 resolveAttr(*i, function, choice->expr->get_result(), choice->env );
1115 } // fi
1116 } // for
1117 } // if
1118 } // if
1119 } // if
1120 } // for
1121 } else {
1122 for ( std::list< DeclarationWithType* >::iterator i = attrList.begin(); i != attrList.end(); ++i ) {
1123 VariableExpr newExpr( *i );
1124 alternatives.push_back( Alternative( newExpr.clone(), env, Cost::zero ) );
1125 renameTypes( alternatives.back().expr );
1126 } // for
1127 } // if
1128 }
1129
1130 void AlternativeFinder::visit( LogicalExpr *logicalExpr ) {
1131 AlternativeFinder firstFinder( indexer, env );
1132 firstFinder.findWithAdjustment( logicalExpr->get_arg1() );
1133 for ( AltList::const_iterator first = firstFinder.alternatives.begin(); first != firstFinder.alternatives.end(); ++first ) {
1134 AlternativeFinder secondFinder( indexer, first->env );
1135 secondFinder.findWithAdjustment( logicalExpr->get_arg2() );
1136 for ( AltList::const_iterator second = secondFinder.alternatives.begin(); second != secondFinder.alternatives.end(); ++second ) {
1137 LogicalExpr *newExpr = new LogicalExpr( first->expr->clone(), second->expr->clone(), logicalExpr->get_isAnd() );
1138 alternatives.push_back( Alternative( newExpr, second->env, first->cost + second->cost ) );
1139 }
1140 }
1141 }
1142
1143 void AlternativeFinder::visit( ConditionalExpr *conditionalExpr ) {
1144 // find alternatives for condition
1145 AlternativeFinder firstFinder( indexer, env );
1146 firstFinder.findWithAdjustment( conditionalExpr->get_arg1() );
1147 for ( AltList::const_iterator first = firstFinder.alternatives.begin(); first != firstFinder.alternatives.end(); ++first ) {
1148 // find alternatives for true expression
1149 AlternativeFinder secondFinder( indexer, first->env );
1150 secondFinder.findWithAdjustment( conditionalExpr->get_arg2() );
1151 for ( AltList::const_iterator second = secondFinder.alternatives.begin(); second != secondFinder.alternatives.end(); ++second ) {
1152 // find alterantives for false expression
1153 AlternativeFinder thirdFinder( indexer, second->env );
1154 thirdFinder.findWithAdjustment( conditionalExpr->get_arg3() );
1155 for ( AltList::const_iterator third = thirdFinder.alternatives.begin(); third != thirdFinder.alternatives.end(); ++third ) {
1156 // unify true and false types, then infer parameters to produce new alternatives
1157 OpenVarSet openVars;
1158 AssertionSet needAssertions, haveAssertions;
1159 Alternative newAlt( 0, third->env, first->cost + second->cost + third->cost );
1160 Type* commonType = nullptr;
1161 if ( unify( second->expr->get_result(), third->expr->get_result(), newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
1162 ConditionalExpr *newExpr = new ConditionalExpr( first->expr->clone(), second->expr->clone(), third->expr->clone() );
1163 newExpr->set_result( commonType ? commonType : second->expr->get_result()->clone() );
1164 // convert both options to the conditional result type
1165 newAlt.cost += computeExpressionConversionCost( newExpr->arg2, newExpr->result, indexer, newAlt.env );
1166 newAlt.cost += computeExpressionConversionCost( newExpr->arg3, newExpr->result, indexer, newAlt.env );
1167 newAlt.expr = newExpr;
1168 inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
1169 } // if
1170 } // for
1171 } // for
1172 } // for
1173 }
1174
1175 void AlternativeFinder::visit( CommaExpr *commaExpr ) {
1176 TypeEnvironment newEnv( env );
1177 Expression *newFirstArg = resolveInVoidContext( commaExpr->get_arg1(), indexer, newEnv );
1178 AlternativeFinder secondFinder( indexer, newEnv );
1179 secondFinder.findWithAdjustment( commaExpr->get_arg2() );
1180 for ( AltList::const_iterator alt = secondFinder.alternatives.begin(); alt != secondFinder.alternatives.end(); ++alt ) {
1181 alternatives.push_back( Alternative( new CommaExpr( newFirstArg->clone(), alt->expr->clone() ), alt->env, alt->cost ) );
1182 } // for
1183 delete newFirstArg;
1184 }
1185
1186 void AlternativeFinder::visit( RangeExpr * rangeExpr ) {
1187 // resolve low and high, accept alternatives whose low and high types unify
1188 AlternativeFinder firstFinder( indexer, env );
1189 firstFinder.findWithAdjustment( rangeExpr->get_low() );
1190 for ( AltList::const_iterator first = firstFinder.alternatives.begin(); first != firstFinder.alternatives.end(); ++first ) {
1191 AlternativeFinder secondFinder( indexer, first->env );
1192 secondFinder.findWithAdjustment( rangeExpr->get_high() );
1193 for ( AltList::const_iterator second = secondFinder.alternatives.begin(); second != secondFinder.alternatives.end(); ++second ) {
1194 OpenVarSet openVars;
1195 AssertionSet needAssertions, haveAssertions;
1196 Alternative newAlt( 0, second->env, first->cost + second->cost );
1197 Type* commonType = nullptr;
1198 if ( unify( first->expr->get_result(), second->expr->get_result(), newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
1199 RangeExpr *newExpr = new RangeExpr( first->expr->clone(), second->expr->clone() );
1200 newExpr->set_result( commonType ? commonType : first->expr->get_result()->clone() );
1201 newAlt.expr = newExpr;
1202 inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
1203 } // if
1204 } // for
1205 } // for
1206 }
1207
1208 void AlternativeFinder::visit( UntypedTupleExpr *tupleExpr ) {
1209 std::list< AlternativeFinder > subExprAlternatives;
1210 findSubExprs( tupleExpr->get_exprs().begin(), tupleExpr->get_exprs().end(), back_inserter( subExprAlternatives ) );
1211 std::list< AltList > possibilities;
1212 combos( subExprAlternatives.begin(), subExprAlternatives.end(), back_inserter( possibilities ) );
1213 for ( std::list< AltList >::const_iterator i = possibilities.begin(); i != possibilities.end(); ++i ) {
1214 std::list< Expression * > exprs;
1215 makeExprList( *i, exprs );
1216
1217 TypeEnvironment compositeEnv;
1218 simpleCombineEnvironments( i->begin(), i->end(), compositeEnv );
1219 alternatives.push_back( Alternative( new TupleExpr( exprs ) , compositeEnv, sumCost( *i ) ) );
1220 } // for
1221 }
1222
1223 void AlternativeFinder::visit( TupleExpr *tupleExpr ) {
1224 alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
1225 }
1226
1227 void AlternativeFinder::visit( ImplicitCopyCtorExpr * impCpCtorExpr ) {
1228 alternatives.push_back( Alternative( impCpCtorExpr->clone(), env, Cost::zero ) );
1229 }
1230
1231 void AlternativeFinder::visit( ConstructorExpr * ctorExpr ) {
1232 AlternativeFinder finder( indexer, env );
1233 // don't prune here, since it's guaranteed all alternatives will have the same type
1234 // (giving the alternatives different types is half of the point of ConstructorExpr nodes)
1235 finder.findWithAdjustment( ctorExpr->get_callExpr(), false );
1236 for ( Alternative & alt : finder.alternatives ) {
1237 alternatives.push_back( Alternative( new ConstructorExpr( alt.expr->clone() ), alt.env, alt.cost ) );
1238 }
1239 }
1240
1241 void AlternativeFinder::visit( TupleIndexExpr *tupleExpr ) {
1242 alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
1243 }
1244
1245 void AlternativeFinder::visit( TupleAssignExpr *tupleAssignExpr ) {
1246 alternatives.push_back( Alternative( tupleAssignExpr->clone(), env, Cost::zero ) );
1247 }
1248
1249 void AlternativeFinder::visit( UniqueExpr *unqExpr ) {
1250 AlternativeFinder finder( indexer, env );
1251 finder.findWithAdjustment( unqExpr->get_expr() );
1252 for ( Alternative & alt : finder.alternatives ) {
1253 // ensure that the id is passed on to the UniqueExpr alternative so that the expressions are "linked"
1254 UniqueExpr * newUnqExpr = new UniqueExpr( alt.expr->clone(), unqExpr->get_id() );
1255 alternatives.push_back( Alternative( newUnqExpr, alt.env, alt.cost ) );
1256 }
1257 }
1258
1259 void AlternativeFinder::visit( StmtExpr *stmtExpr ) {
1260 StmtExpr * newStmtExpr = stmtExpr->clone();
1261 ResolvExpr::resolveStmtExpr( newStmtExpr, indexer );
1262 // xxx - this env is almost certainly wrong, and needs to somehow contain the combined environments from all of the statements in the stmtExpr...
1263 alternatives.push_back( Alternative( newStmtExpr, env, Cost::zero ) );
1264 }
1265
1266 void AlternativeFinder::visit( UntypedInitExpr *initExpr ) {
1267 // handle each option like a cast
1268 AltList candidates;
1269 PRINT( std::cerr << "untyped init expr: " << initExpr << std::endl; )
1270 // O(N^2) checks of d-types with e-types
1271 for ( InitAlternative & initAlt : initExpr->get_initAlts() ) {
1272 Type * toType = resolveTypeof( initAlt.type, indexer );
1273 SymTab::validateType( toType, &indexer );
1274 adjustExprType( toType, env, indexer );
1275 // Ideally the call to findWithAdjustment could be moved out of the loop, but unfortunately it currently has to occur inside or else
1276 // polymorphic return types are not properly bound to the initialization type, since return type variables are only open for the duration of resolving
1277 // the UntypedExpr. This is only actually an issue in initialization contexts that allow more than one possible initialization type, but it is still suboptimal.
1278 AlternativeFinder finder( indexer, env );
1279 finder.targetType = toType;
1280 finder.findWithAdjustment( initExpr->get_expr() );
1281 for ( Alternative & alt : finder.get_alternatives() ) {
1282 TypeEnvironment newEnv( alt.env );
1283 AssertionSet needAssertions, haveAssertions;
1284 OpenVarSet openVars; // find things in env that don't have a "representative type" and claim those are open vars?
1285 PRINT( std::cerr << " @ " << toType << " " << initAlt.designation << std::endl; )
1286 // It's possible that a cast can throw away some values in a multiply-valued expression. (An example is a
1287 // cast-to-void, which casts from one value to zero.) Figure out the prefix of the subexpression results
1288 // that are cast directly. The candidate is invalid if it has fewer results than there are types to cast
1289 // to.
1290 int discardedValues = alt.expr->get_result()->size() - toType->size();
1291 if ( discardedValues < 0 ) continue;
1292 // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
1293 // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
1294 // unification run for side-effects
1295 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??
1296
1297 Cost thisCost = castCost( alt.expr->get_result(), toType, indexer, newEnv );
1298 if ( thisCost != Cost::infinity ) {
1299 // count one safe conversion for each value that is thrown away
1300 thisCost.incSafe( discardedValues );
1301 candidates.push_back( Alternative( new InitExpr( restructureCast( alt.expr->clone(), toType ), initAlt.designation->clone() ), newEnv, alt.cost, thisCost ) );
1302 }
1303 }
1304 }
1305
1306 // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the
1307 // cvtCost member to the cost member (since the old cost is now irrelevant). Thus, calling findMinCost twice
1308 // selects first based on argument cost, then on conversion cost.
1309 AltList minArgCost;
1310 findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) );
1311 findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );
1312 }
1313} // namespace ResolvExpr
1314
1315// Local Variables: //
1316// tab-width: 4 //
1317// mode: c++ //
1318// compile-command: "make install" //
1319// End: //
Note: See TracBrowser for help on using the repository browser.