source: src/ResolvExpr/AlternativeFinder.cc@ 83a071f9

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

Add reference to rvalue conversions to functions when resolving UntypedExpr

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