source: src/ResolvExpr/AlternativeFinder.cc@ bcef6c8

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 bcef6c8 was 93401f8, checked in by Peter A. Buhr <pabuhr@…>, 8 years ago

add space in error message

  • Property mode set to 100644
File size: 73.7 KB
RevLine 
[a32b204]1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
[6ed1d4b]7// AlternativeFinder.cc --
[a32b204]8//
9// Author : Richard C. Bilson
10// Created On : Sat May 16 23:52:08 2015
[b128d3e]11// Last Modified By : Peter A. Buhr
[93401f8]12// Last Modified On : Sat Feb 17 11:19:39 2018
13// Update Count : 33
[a32b204]14//
15
[ea6332d]16#include <algorithm> // for copy
[e3e16bc]17#include <cassert> // for strict_dynamic_cast, assert, assertf
[403b388]18#include <cstddef> // for size_t
[ea6332d]19#include <iostream> // for operator<<, cerr, ostream, endl
20#include <iterator> // for back_insert_iterator, back_inserter
21#include <list> // for _List_iterator, list, _List_const_...
22#include <map> // for _Rb_tree_iterator, map, _Rb_tree_c...
[403b388]23#include <memory> // for allocator_traits<>::value_type, unique_ptr
[ea6332d]24#include <utility> // for pair
[aeb75b1]25#include <vector> // for vector
[51b73452]26
[ea6332d]27#include "Alternative.h" // for AltList, Alternative
[51b73452]28#include "AlternativeFinder.h"
[ea6332d]29#include "Common/SemanticError.h" // for SemanticError
30#include "Common/utility.h" // for deleteAll, printAll, CodeLocation
31#include "Cost.h" // for Cost, Cost::zero, operator<<, Cost...
[a8b27c6]32#include "ExplodedActual.h" // for ExplodedActual
[ea6332d]33#include "InitTweak/InitTweak.h" // for getFunctionName
34#include "RenameVars.h" // for RenameVars, global_renamer
35#include "ResolveTypeof.h" // for resolveTypeof
36#include "Resolver.h" // for resolveStmtExpr
37#include "SymTab/Indexer.h" // for Indexer
38#include "SymTab/Mangler.h" // for Mangler
39#include "SymTab/Validate.h" // for validateType
40#include "SynTree/Constant.h" // for Constant
41#include "SynTree/Declaration.h" // for DeclarationWithType, TypeDecl, Dec...
42#include "SynTree/Expression.h" // for Expression, CastExpr, NameExpr
43#include "SynTree/Initializer.h" // for SingleInit, operator<<, Designation
44#include "SynTree/SynTree.h" // for UniqueId
45#include "SynTree/Type.h" // for Type, FunctionType, PointerType
46#include "Tuples/Explode.h" // for explode
47#include "Tuples/Tuples.h" // for isTtype, handleTupleAssignment
48#include "Unify.h" // for unify
49#include "typeops.h" // for adjustExprType, polyCost, castCost
[51b73452]50
[b87a5ed]51extern bool resolvep;
[6ed1d4b]52#define PRINT( text ) if ( resolvep ) { text }
[51b73452]53//#define DEBUG_COST
54
[403b388]55using std::move;
56
57/// copies any copyable type
58template<typename T>
59T copy(const T& x) { return x; }
60
[51b73452]61namespace ResolvExpr {
[13deae88]62 struct AlternativeFinder::Finder : public WithShortCircuiting {
63 Finder( AlternativeFinder & altFinder ) : altFinder( altFinder ), indexer( altFinder.indexer ), alternatives( altFinder.alternatives ), env( altFinder.env ), targetType( altFinder.targetType ) {}
64
65 void previsit( BaseSyntaxNode * ) { visit_children = false; }
66
67 void postvisit( ApplicationExpr * applicationExpr );
68 void postvisit( UntypedExpr * untypedExpr );
69 void postvisit( AddressExpr * addressExpr );
70 void postvisit( LabelAddressExpr * labelExpr );
71 void postvisit( CastExpr * castExpr );
72 void postvisit( VirtualCastExpr * castExpr );
73 void postvisit( UntypedMemberExpr * memberExpr );
74 void postvisit( MemberExpr * memberExpr );
75 void postvisit( NameExpr * variableExpr );
76 void postvisit( VariableExpr * variableExpr );
77 void postvisit( ConstantExpr * constantExpr );
78 void postvisit( SizeofExpr * sizeofExpr );
79 void postvisit( AlignofExpr * alignofExpr );
80 void postvisit( UntypedOffsetofExpr * offsetofExpr );
81 void postvisit( OffsetofExpr * offsetofExpr );
82 void postvisit( OffsetPackExpr * offsetPackExpr );
83 void postvisit( AttrExpr * attrExpr );
84 void postvisit( LogicalExpr * logicalExpr );
85 void postvisit( ConditionalExpr * conditionalExpr );
86 void postvisit( CommaExpr * commaExpr );
87 void postvisit( ImplicitCopyCtorExpr * impCpCtorExpr );
88 void postvisit( ConstructorExpr * ctorExpr );
89 void postvisit( RangeExpr * rangeExpr );
90 void postvisit( UntypedTupleExpr * tupleExpr );
91 void postvisit( TupleExpr * tupleExpr );
92 void postvisit( TupleIndexExpr * tupleExpr );
93 void postvisit( TupleAssignExpr * tupleExpr );
94 void postvisit( UniqueExpr * unqExpr );
95 void postvisit( StmtExpr * stmtExpr );
96 void postvisit( UntypedInitExpr * initExpr );
[c71b256]97 void postvisit( InitExpr * initExpr );
98 void postvisit( DeletedExpr * delExpr );
[13deae88]99
100 /// Adds alternatives for anonymous members
101 void addAnonConversions( const Alternative & alt );
102 /// Adds alternatives for member expressions, given the aggregate, conversion cost for that aggregate, and name of the member
103 template< typename StructOrUnionType > void addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member );
104 /// Adds alternatives for member expressions where the left side has tuple type
105 void addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member );
106 /// Adds alternatives for offsetof expressions, given the base type and name of the member
107 template< typename StructOrUnionType > void addOffsetof( StructOrUnionType *aggInst, const std::string &name );
108 /// Takes a final result and checks if its assertions can be satisfied
109 template<typename OutputIterator>
110 void validateFunctionAlternative( const Alternative &func, ArgPack& result, const std::vector<ArgPack>& results, OutputIterator out );
111 /// Finds matching alternatives for a function, given a set of arguments
112 template<typename OutputIterator>
113 void makeFunctionAlternatives( const Alternative &func, FunctionType *funcType, const ExplodedArgs& args, OutputIterator out );
114 /// Checks if assertion parameters match for a new alternative
115 template< typename OutputIterator >
116 void inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out );
117 private:
118 AlternativeFinder & altFinder;
119 const SymTab::Indexer &indexer;
120 AltList & alternatives;
121 const TypeEnvironment &env;
122 Type *& targetType;
123 };
124
[908cc83]125 Cost sumCost( const AltList &in ) {
[89be1c68]126 Cost total = Cost::zero;
[908cc83]127 for ( AltList::const_iterator i = in.begin(); i != in.end(); ++i ) {
128 total += i->cost;
129 }
130 return total;
131 }
132
[1e8bbac9]133 void printAlts( const AltList &list, std::ostream &os, unsigned int indentAmt ) {
134 Indenter indent = { Indenter::tabsize, indentAmt };
135 for ( AltList::const_iterator i = list.begin(); i != list.end(); ++i ) {
136 i->print( os, indent );
137 os << std::endl;
[a32b204]138 }
[1e8bbac9]139 }
[d9a0e76]140
[1e8bbac9]141 namespace {
[a32b204]142 void makeExprList( const AltList &in, std::list< Expression* > &out ) {
143 for ( AltList::const_iterator i = in.begin(); i != in.end(); ++i ) {
144 out.push_back( i->expr->clone() );
145 }
146 }
[d9a0e76]147
[a32b204]148 struct PruneStruct {
149 bool isAmbiguous;
150 AltList::iterator candidate;
151 PruneStruct() {}
152 PruneStruct( AltList::iterator candidate ): isAmbiguous( false ), candidate( candidate ) {}
153 };
154
[0f19d763]155 /// Prunes a list of alternatives down to those that have the minimum conversion cost for a given return type; skips ambiguous interpretations
[a32b204]156 template< typename InputIterator, typename OutputIterator >
[d7dc824]157 void pruneAlternatives( InputIterator begin, InputIterator end, OutputIterator out ) {
[a32b204]158 // select the alternatives that have the minimum conversion cost for a particular set of result types
159 std::map< std::string, PruneStruct > selected;
160 for ( AltList::iterator candidate = begin; candidate != end; ++candidate ) {
161 PruneStruct current( candidate );
162 std::string mangleName;
[906e24d]163 {
164 Type * newType = candidate->expr->get_result()->clone();
[a32b204]165 candidate->env.apply( newType );
[906e24d]166 mangleName = SymTab::Mangler::mangle( newType );
[a32b204]167 delete newType;
168 }
169 std::map< std::string, PruneStruct >::iterator mapPlace = selected.find( mangleName );
170 if ( mapPlace != selected.end() ) {
171 if ( candidate->cost < mapPlace->second.candidate->cost ) {
172 PRINT(
[6ed1d4b]173 std::cerr << "cost " << candidate->cost << " beats " << mapPlace->second.candidate->cost << std::endl;
[7c64920]174 )
[0f19d763]175 selected[ mangleName ] = current;
[a32b204]176 } else if ( candidate->cost == mapPlace->second.candidate->cost ) {
177 PRINT(
[6ed1d4b]178 std::cerr << "marking ambiguous" << std::endl;
[7c64920]179 )
[0f19d763]180 mapPlace->second.isAmbiguous = true;
[b0837e4]181 } else {
182 PRINT(
183 std::cerr << "cost " << candidate->cost << " loses to " << mapPlace->second.candidate->cost << std::endl;
184 )
[a32b204]185 }
186 } else {
187 selected[ mangleName ] = current;
188 }
189 }
[d9a0e76]190
[0f19d763]191 // accept the alternatives that were unambiguous
192 for ( std::map< std::string, PruneStruct >::iterator target = selected.begin(); target != selected.end(); ++target ) {
193 if ( ! target->second.isAmbiguous ) {
194 Alternative &alt = *target->second.candidate;
[906e24d]195 alt.env.applyFree( alt.expr->get_result() );
[0f19d763]196 *out++ = alt;
[a32b204]197 }
[0f19d763]198 }
[d9a0e76]199 }
[a32b204]200
201 void renameTypes( Expression *expr ) {
[ad51cc2]202 renameTyVars( expr->result );
[e76acbe]203 }
[1dcd9554]204 } // namespace
[b1bead1]205
[1dcd9554]206 void referenceToRvalueConversion( Expression *& expr ) {
207 if ( dynamic_cast< ReferenceType * >( expr->get_result() ) ) {
208 // cast away reference from expr
209 expr = new CastExpr( expr, expr->get_result()->stripReferences()->clone() );
[b1bead1]210 }
[1dcd9554]211 }
[d9a0e76]212
[a32b204]213 template< typename InputIterator, typename OutputIterator >
214 void AlternativeFinder::findSubExprs( InputIterator begin, InputIterator end, OutputIterator out ) {
215 while ( begin != end ) {
216 AlternativeFinder finder( indexer, env );
217 finder.findWithAdjustment( *begin );
218 // XXX either this
219 //Designators::fixDesignations( finder, (*begin++)->get_argName() );
220 // or XXX this
221 begin++;
222 PRINT(
[6ed1d4b]223 std::cerr << "findSubExprs" << std::endl;
224 printAlts( finder.alternatives, std::cerr );
[7c64920]225 )
[0f19d763]226 *out++ = finder;
[a32b204]227 }
[d9a0e76]228 }
229
[a32b204]230 AlternativeFinder::AlternativeFinder( const SymTab::Indexer &indexer, const TypeEnvironment &env )
231 : indexer( indexer ), env( env ) {
[d9a0e76]232 }
[51b73452]233
[4e66a18]234 void AlternativeFinder::find( Expression *expr, bool adjust, bool prune, bool failFast ) {
[13deae88]235 PassVisitor<Finder> finder( *this );
236 expr->accept( finder );
[4e66a18]237 if ( failFast && alternatives.empty() ) {
[83882e9]238 PRINT(
239 std::cerr << "No reasonable alternatives for expression " << expr << std::endl;
240 )
[d55d7a6]241 throw SemanticError( expr, "No reasonable alternatives for expression " );
[a32b204]242 }
[b6fe7e6]243 if ( prune ) {
[b0837e4]244 auto oldsize = alternatives.size();
[b6fe7e6]245 PRINT(
246 std::cerr << "alternatives before prune:" << std::endl;
247 printAlts( alternatives, std::cerr );
248 )
[bd4f2e9]249 AltList pruned;
250 pruneAlternatives( alternatives.begin(), alternatives.end(), back_inserter( pruned ) );
251 if ( failFast && pruned.empty() ) {
[b6fe7e6]252 std::ostringstream stream;
253 AltList winners;
254 findMinCost( alternatives.begin(), alternatives.end(), back_inserter( winners ) );
[50377a4]255 stream << "Cannot choose between " << winners.size() << " alternatives for expression\n";
[5a824c2]256 expr->print( stream );
[93401f8]257 stream << " Alternatives are:\n";
[50377a4]258 printAlts( winners, stream, 1 );
[d55d7a6]259 throw SemanticError( expr->location, stream.str() );
[b6fe7e6]260 }
[bd4f2e9]261 alternatives = move(pruned);
[b0837e4]262 PRINT(
263 std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl;
264 )
[b6fe7e6]265 PRINT(
266 std::cerr << "there are " << alternatives.size() << " alternatives after elimination" << std::endl;
267 )
[a32b204]268 }
[954ef5b]269 // adjust types after pruning so that types substituted by pruneAlternatives are correctly adjusted
270 for ( AltList::iterator i = alternatives.begin(); i != alternatives.end(); ++i ) {
271 if ( adjust ) {
272 adjustExprType( i->expr->get_result(), i->env, indexer );
273 }
274 }
[8e9cbb2]275
[64ac636]276 // Central location to handle gcc extension keyword, etc. for all expression types.
[8e9cbb2]277 for ( Alternative &iter: alternatives ) {
278 iter.expr->set_extension( expr->get_extension() );
[64ac636]279 iter.expr->location = expr->location;
[8e9cbb2]280 } // for
[0f19d763]281 }
[d9a0e76]282
[4e66a18]283 void AlternativeFinder::findWithAdjustment( Expression *expr ) {
284 find( expr, true );
285 }
286
287 void AlternativeFinder::findWithoutPrune( Expression * expr ) {
288 find( expr, true, false );
289 }
290
291 void AlternativeFinder::maybeFind( Expression * expr ) {
292 find( expr, true, true, false );
[d9a0e76]293 }
[a32b204]294
[13deae88]295 void AlternativeFinder::Finder::addAnonConversions( const Alternative & alt ) {
[4b0f997]296 // adds anonymous member interpretations whenever an aggregate value type is seen.
[d1685588]297 // 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
298 std::unique_ptr<Expression> aggrExpr( alt.expr->clone() );
299 alt.env.apply( aggrExpr->get_result() );
300 Type * aggrType = aggrExpr->get_result();
301 if ( dynamic_cast< ReferenceType * >( aggrType ) ) {
302 aggrType = aggrType->stripReferences();
303 aggrExpr.reset( new CastExpr( aggrExpr.release(), aggrType->clone() ) );
304 }
305
306 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) {
[4b0f997]307 NameExpr nameExpr( "" );
[d1685588]308 addAggMembers( structInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, &nameExpr );
309 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) {
[4b0f997]310 NameExpr nameExpr( "" );
[d1685588]311 addAggMembers( unionInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, &nameExpr );
[4b0f997]312 } // if
313 }
[77971f6]314
[a32b204]315 template< typename StructOrUnionType >
[13deae88]316 void AlternativeFinder::Finder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
[bf32bb8]317 // by this point, member must be a name expr
[c93bc28]318 NameExpr * nameExpr = dynamic_cast< NameExpr * >( member );
319 if ( ! nameExpr ) return;
[bf32bb8]320 const std::string & name = nameExpr->get_name();
321 std::list< Declaration* > members;
322 aggInst->lookup( name, members );
[4b0f997]323
[bf32bb8]324 for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) {
325 if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) {
[d9fa60a]326 alternatives.push_back( Alternative( new MemberExpr( dwt, expr->clone() ), env, newCost ) );
[bf32bb8]327 renameTypes( alternatives.back().expr );
[4b0f997]328 addAnonConversions( alternatives.back() ); // add anonymous member interpretations whenever an aggregate value type is seen as a member expression.
[bf32bb8]329 } else {
330 assert( false );
[a32b204]331 }
332 }
[d9a0e76]333 }
[a32b204]334
[13deae88]335 void AlternativeFinder::Finder::addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) {
[848ce71]336 if ( ConstantExpr * constantExpr = dynamic_cast< ConstantExpr * >( member ) ) {
337 // get the value of the constant expression as an int, must be between 0 and the length of the tuple type to have meaning
338 // xxx - this should be improved by memoizing the value of constant exprs
339 // during parsing and reusing that information here.
340 std::stringstream ss( constantExpr->get_constant()->get_value() );
[c93bc28]341 int val = 0;
[848ce71]342 std::string tmp;
343 if ( ss >> val && ! (ss >> tmp) ) {
344 if ( val >= 0 && (unsigned int)val < tupleType->size() ) {
345 alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) );
346 } // if
347 } // if
[141b786]348 } else if ( NameExpr * nameExpr = dynamic_cast< NameExpr * >( member ) ) {
349 // xxx - temporary hack until 0/1 are int constants
350 if ( nameExpr->get_name() == "0" || nameExpr->get_name() == "1" ) {
351 std::stringstream ss( nameExpr->get_name() );
352 int val;
353 ss >> val;
354 alternatives.push_back( Alternative( new TupleIndexExpr( expr->clone(), val ), env, newCost ) );
355 }
[848ce71]356 } // if
357 }
358
[13deae88]359 void AlternativeFinder::Finder::postvisit( ApplicationExpr *applicationExpr ) {
[a32b204]360 alternatives.push_back( Alternative( applicationExpr->clone(), env, Cost::zero ) );
[d9a0e76]361 }
362
[ddf8a29]363 Cost computeConversionCost( Type * actualType, Type * formalType, const SymTab::Indexer &indexer, const TypeEnvironment & env ) {
364 PRINT(
365 std::cerr << std::endl << "converting ";
366 actualType->print( std::cerr, 8 );
367 std::cerr << std::endl << " to ";
368 formalType->print( std::cerr, 8 );
369 std::cerr << std::endl << "environment is: ";
370 env.print( std::cerr, 8 );
371 std::cerr << std::endl;
372 )
373 Cost convCost = conversionCost( actualType, formalType, indexer, env );
374 PRINT(
[d06c808]375 std::cerr << std::endl << "cost is " << convCost << std::endl;
[ddf8a29]376 )
377 if ( convCost == Cost::infinity ) {
378 return convCost;
379 }
380 convCost.incPoly( polyCost( formalType, env, indexer ) + polyCost( actualType, env, indexer ) );
[d06c808]381 PRINT(
382 std::cerr << "cost with polycost is " << convCost << std::endl;
383 )
[ddf8a29]384 return convCost;
385 }
386
387 Cost computeExpressionConversionCost( Expression *& actualExpr, Type * formalType, const SymTab::Indexer &indexer, const TypeEnvironment & env ) {
388 Cost convCost = computeConversionCost( actualExpr->result, formalType, indexer, env );
389
[bb666f64]390 // if there is a non-zero conversion cost, ignoring poly cost, then the expression requires conversion.
391 // ignore poly cost for now, since this requires resolution of the cast to infer parameters and this
392 // does not currently work for the reason stated below.
[ddf8a29]393 Cost tmpCost = convCost;
394 tmpCost.incPoly( -tmpCost.get_polyCost() );
395 if ( tmpCost != Cost::zero ) {
396 Type *newType = formalType->clone();
397 env.apply( newType );
398 actualExpr = new CastExpr( actualExpr, newType );
399 // 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
400 // inconsistent, once this is fixed it should be possible to resolve the cast.
401 // 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.
402
403 // AlternativeFinder finder( indexer, env );
404 // finder.findWithAdjustment( actualExpr );
405 // assertf( finder.get_alternatives().size() > 0, "Somehow castable expression failed to find alternatives." );
406 // assertf( finder.get_alternatives().size() == 1, "Somehow got multiple alternatives for known cast expression." );
407 // Alternative & alt = finder.get_alternatives().front();
408 // delete actualExpr;
409 // actualExpr = alt.expr->clone();
410 }
411 return convCost;
412 }
413
414 Cost computeApplicationConversionCost( Alternative &alt, const SymTab::Indexer &indexer ) {
[e3e16bc]415 ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( alt.expr );
416 PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
417 FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->get_base() );
[a32b204]418
[89be1c68]419 Cost convCost = Cost::zero;
[a32b204]420 std::list< DeclarationWithType* >& formals = function->get_parameters();
421 std::list< DeclarationWithType* >::iterator formal = formals.begin();
422 std::list< Expression* >& actuals = appExpr->get_args();
[0362d42]423
[a32b204]424 for ( std::list< Expression* >::iterator actualExpr = actuals.begin(); actualExpr != actuals.end(); ++actualExpr ) {
[53e3b4a]425 Type * actualType = (*actualExpr)->get_result();
[a32b204]426 PRINT(
[6ed1d4b]427 std::cerr << "actual expression:" << std::endl;
428 (*actualExpr)->print( std::cerr, 8 );
429 std::cerr << "--- results are" << std::endl;
[53e3b4a]430 actualType->print( std::cerr, 8 );
[7c64920]431 )
[53e3b4a]432 if ( formal == formals.end() ) {
433 if ( function->get_isVarArgs() ) {
[89be1c68]434 convCost.incUnsafe();
[d06c808]435 PRINT( std::cerr << "end of formals with varargs function: inc unsafe: " << convCost << std::endl; ; )
[b1bead1]436 // convert reference-typed expressions to value-typed expressions
437 referenceToRvalueConversion( *actualExpr );
[53e3b4a]438 continue;
439 } else {
440 return Cost::infinity;
[7c64920]441 }
[53e3b4a]442 }
443 Type * formalType = (*formal)->get_type();
[ddf8a29]444 convCost += computeExpressionConversionCost( *actualExpr, formalType, indexer, alt.env );
[53e3b4a]445 ++formal; // can't be in for-loop update because of the continue
[d9a0e76]446 }
[a32b204]447 if ( formal != formals.end() ) {
448 return Cost::infinity;
[d9a0e76]449 }
450
[a32b204]451 for ( InferredParams::const_iterator assert = appExpr->get_inferParams().begin(); assert != appExpr->get_inferParams().end(); ++assert ) {
[ddf8a29]452 convCost += computeConversionCost( assert->second.actualType, assert->second.formalType, indexer, alt.env );
[a32b204]453 }
[d9a0e76]454
[a32b204]455 return convCost;
456 }
[d9a0e76]457
[8c84ebd]458 /// Adds type variables to the open variable set and marks their assertions
[a32b204]459 void makeUnifiableVars( Type *type, OpenVarSet &unifiableVars, AssertionSet &needAssertions ) {
[8c49c0e]460 for ( Type::ForallList::const_iterator tyvar = type->get_forall().begin(); tyvar != type->get_forall().end(); ++tyvar ) {
[2c57025]461 unifiableVars[ (*tyvar)->get_name() ] = TypeDecl::Data{ *tyvar };
[a32b204]462 for ( std::list< DeclarationWithType* >::iterator assert = (*tyvar)->get_assertions().begin(); assert != (*tyvar)->get_assertions().end(); ++assert ) {
[6c3a988f]463 needAssertions[ *assert ].isUsed = true;
[a32b204]464 }
[d9a0e76]465/// needAssertions.insert( needAssertions.end(), (*tyvar)->get_assertions().begin(), (*tyvar)->get_assertions().end() );
466 }
467 }
[a32b204]468
[89b686a]469 // /// Map of declaration uniqueIds (intended to be the assertions in an AssertionSet) to their parents and the number of times they've been included
470 //typedef std::unordered_map< UniqueId, std::unordered_map< UniqueId, unsigned > > AssertionParentSet;
[79970ed]471
[a1d7679]472 static const int recursionLimit = /*10*/ 4; ///< Limit to depth of recursion satisfaction
[89b686a]473 //static const unsigned recursionParentLimit = 1; ///< Limit to the number of times an assertion can recursively use itself
[51b73452]474
[a32b204]475 void addToIndexer( AssertionSet &assertSet, SymTab::Indexer &indexer ) {
476 for ( AssertionSet::iterator i = assertSet.begin(); i != assertSet.end(); ++i ) {
[6c3a988f]477 if ( i->second.isUsed ) {
[33a25f9]478 indexer.addId( i->first );
[a32b204]479 }
480 }
[d9a0e76]481 }
[79970ed]482
[a32b204]483 template< typename ForwardIterator, typename OutputIterator >
[79970ed]484 void inferRecursive( ForwardIterator begin, ForwardIterator end, const Alternative &newAlt, OpenVarSet &openVars, const SymTab::Indexer &decls, const AssertionSet &newNeed, /*const AssertionParentSet &needParents,*/
[ebf5689]485 int level, const SymTab::Indexer &indexer, OutputIterator out ) {
[a32b204]486 if ( begin == end ) {
487 if ( newNeed.empty() ) {
[6c3a988f]488 PRINT(
489 std::cerr << "all assertions satisfied, output alternative: ";
490 newAlt.print( std::cerr );
491 std::cerr << std::endl;
492 );
[a32b204]493 *out++ = newAlt;
494 return;
495 } else if ( level >= recursionLimit ) {
[d55d7a6]496 throw SemanticError( newAlt.expr->location, "Too many recursive assertions" );
[a32b204]497 } else {
498 AssertionSet newerNeed;
499 PRINT(
500 std::cerr << "recursing with new set:" << std::endl;
501 printAssertionSet( newNeed, std::cerr, 8 );
[7c64920]502 )
[89b686a]503 inferRecursive( newNeed.begin(), newNeed.end(), newAlt, openVars, decls, newerNeed, /*needParents,*/ level+1, indexer, out );
[a32b204]504 return;
505 }
506 }
507
508 ForwardIterator cur = begin++;
[6c3a988f]509 if ( ! cur->second.isUsed ) {
[89b686a]510 inferRecursive( begin, end, newAlt, openVars, decls, newNeed, /*needParents,*/ level, indexer, out );
[7933351]511 return; // xxx - should this continue? previously this wasn't here, and it looks like it should be
[a32b204]512 }
513 DeclarationWithType *curDecl = cur->first;
[7933351]514
[d9a0e76]515 PRINT(
[a32b204]516 std::cerr << "inferRecursive: assertion is ";
517 curDecl->print( std::cerr );
518 std::cerr << std::endl;
[7c64920]519 )
[a40d503]520 std::list< SymTab::Indexer::IdData > candidates;
[a32b204]521 decls.lookupId( curDecl->get_name(), candidates );
[6ed1d4b]522/// if ( candidates.empty() ) { std::cerr << "no candidates!" << std::endl; }
[a40d503]523 for ( const auto & data : candidates ) {
524 DeclarationWithType * candidate = data.id;
[a32b204]525 PRINT(
[6ed1d4b]526 std::cerr << "inferRecursive: candidate is ";
[a40d503]527 candidate->print( std::cerr );
[6ed1d4b]528 std::cerr << std::endl;
[7c64920]529 )
[79970ed]530
[0f19d763]531 AssertionSet newHave, newerNeed( newNeed );
[a32b204]532 TypeEnvironment newEnv( newAlt.env );
533 OpenVarSet newOpenVars( openVars );
[a40d503]534 Type *adjType = candidate->get_type()->clone();
[a32b204]535 adjustExprType( adjType, newEnv, indexer );
[ad51cc2]536 renameTyVars( adjType );
[a32b204]537 PRINT(
538 std::cerr << "unifying ";
539 curDecl->get_type()->print( std::cerr );
540 std::cerr << " with ";
541 adjType->print( std::cerr );
542 std::cerr << std::endl;
[7c64920]543 )
[0f19d763]544 if ( unify( curDecl->get_type(), adjType, newEnv, newerNeed, newHave, newOpenVars, indexer ) ) {
545 PRINT(
546 std::cerr << "success!" << std::endl;
[a32b204]547 )
[0f19d763]548 SymTab::Indexer newDecls( decls );
549 addToIndexer( newHave, newDecls );
550 Alternative newerAlt( newAlt );
551 newerAlt.env = newEnv;
[a40d503]552 assertf( candidate->get_uniqueId(), "Assertion candidate does not have a unique ID: %s", toString( candidate ).c_str() );
[6c3a988f]553
554 // everything with an empty idChain was pulled in by the current assertion.
555 // add current assertion's idChain + current assertion's ID so that the correct inferParameters can be found.
556 for ( auto & a : newerNeed ) {
557 if ( a.second.idChain.empty() ) {
558 a.second.idChain = cur->second.idChain;
559 a.second.idChain.push_back( curDecl->get_uniqueId() );
560 }
561 }
562
[89b686a]563 //AssertionParentSet newNeedParents( needParents );
[22cad76]564 // skip repeatingly-self-recursive assertion satisfaction
[89b686a]565 // DOESN'T WORK: grandchild nodes conflict with their cousins
566 //if ( newNeedParents[ curDecl->get_uniqueId() ][ candDecl->get_uniqueId() ]++ > recursionParentLimit ) continue;
[a40d503]567 Expression *varExpr = data.combine();
[906e24d]568 delete varExpr->get_result();
569 varExpr->set_result( adjType->clone() );
[0f19d763]570 PRINT(
[6ed1d4b]571 std::cerr << "satisfying assertion " << curDecl->get_uniqueId() << " ";
572 curDecl->print( std::cerr );
[a40d503]573 std::cerr << " with declaration " << candidate->get_uniqueId() << " ";
574 candidate->print( std::cerr );
[6ed1d4b]575 std::cerr << std::endl;
[7c64920]576 )
[6c3a988f]577 // 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).
[df626eb]578 InferredParams * inferParameters = &newerAlt.expr->get_inferParams();
[6c3a988f]579 for ( UniqueId id : cur->second.idChain ) {
580 inferParameters = (*inferParameters)[ id ].inferParams.get();
581 }
[0f19d763]582 // XXX: this is a memory leak, but adjType can't be deleted because it might contain assertions
[a40d503]583 (*inferParameters)[ curDecl->get_uniqueId() ] = ParamEntry( candidate->get_uniqueId(), adjType->clone(), curDecl->get_type()->clone(), varExpr );
[89b686a]584 inferRecursive( begin, end, newerAlt, newOpenVars, newDecls, newerNeed, /*newNeedParents,*/ level, indexer, out );
[0f19d763]585 } else {
586 delete adjType;
587 }
[a32b204]588 }
[d9a0e76]589 }
590
[a32b204]591 template< typename OutputIterator >
[13deae88]592 void AlternativeFinder::Finder::inferParameters( const AssertionSet &need, AssertionSet &have, const Alternative &newAlt, OpenVarSet &openVars, OutputIterator out ) {
[d9a0e76]593// PRINT(
[6ed1d4b]594// std::cerr << "inferParameters: assertions needed are" << std::endl;
595// printAll( need, std::cerr, 8 );
[d9a0e76]596// )
[a32b204]597 SymTab::Indexer decls( indexer );
[e4d829b]598 // PRINT(
599 // std::cerr << "============= original indexer" << std::endl;
600 // indexer.print( std::cerr );
601 // std::cerr << "============= new indexer" << std::endl;
602 // decls.print( std::cerr );
603 // )
[0f19d763]604 addToIndexer( have, decls );
[a32b204]605 AssertionSet newNeed;
[89b686a]606 //AssertionParentSet needParents;
[74b007ba]607 PRINT(
608 std::cerr << "env is: " << std::endl;
609 newAlt.env.print( std::cerr, 0 );
610 std::cerr << std::endl;
611 )
612
[89b686a]613 inferRecursive( need.begin(), need.end(), newAlt, openVars, decls, newNeed, /*needParents,*/ 0, indexer, out );
[d9a0e76]614// PRINT(
[6ed1d4b]615// std::cerr << "declaration 14 is ";
[d9a0e76]616// Declaration::declFromId
617// *out++ = newAlt;
618// )
619 }
620
[aeb75b1]621 /// Gets a default value from an initializer, nullptr if not present
622 ConstantExpr* getDefaultValue( Initializer* init ) {
623 if ( SingleInit* si = dynamic_cast<SingleInit*>( init ) ) {
624 if ( CastExpr* ce = dynamic_cast<CastExpr*>( si->get_value() ) ) {
625 return dynamic_cast<ConstantExpr*>( ce->get_arg() );
626 }
627 }
628 return nullptr;
629 }
630
631 /// State to iteratively build a match of parameter expressions to arguments
632 struct ArgPack {
[452747a]633 std::size_t parent; ///< Index of parent pack
[403b388]634 std::unique_ptr<Expression> expr; ///< The argument stored here
635 Cost cost; ///< The cost of this argument
636 TypeEnvironment env; ///< Environment for this pack
637 AssertionSet need; ///< Assertions outstanding for this pack
638 AssertionSet have; ///< Assertions found for this pack
639 OpenVarSet openVars; ///< Open variables for this pack
640 unsigned nextArg; ///< Index of next argument in arguments list
641 unsigned tupleStart; ///< Number of tuples that start at this index
[a8b27c6]642 unsigned nextExpl; ///< Index of next exploded element
643 unsigned explAlt; ///< Index of alternative for nextExpl > 0
[403b388]644
645 ArgPack()
[ad51cc2]646 : parent(0), expr(), cost(Cost::zero), env(), need(), have(), openVars(), nextArg(0),
[a8b27c6]647 tupleStart(0), nextExpl(0), explAlt(0) {}
[aeb75b1]648
[11094d9]649 ArgPack(const TypeEnvironment& env, const AssertionSet& need, const AssertionSet& have,
[aeb75b1]650 const OpenVarSet& openVars)
[452747a]651 : parent(0), expr(), cost(Cost::zero), env(env), need(need), have(have),
[a8b27c6]652 openVars(openVars), nextArg(0), tupleStart(0), nextExpl(0), explAlt(0) {}
[11094d9]653
[452747a]654 ArgPack(std::size_t parent, Expression* expr, TypeEnvironment&& env, AssertionSet&& need,
655 AssertionSet&& have, OpenVarSet&& openVars, unsigned nextArg,
[178e4ec]656 unsigned tupleStart = 0, Cost cost = Cost::zero, unsigned nextExpl = 0,
[a8b27c6]657 unsigned explAlt = 0 )
[452747a]658 : parent(parent), expr(expr->clone()), cost(cost), env(move(env)), need(move(need)),
[403b388]659 have(move(have)), openVars(move(openVars)), nextArg(nextArg), tupleStart(tupleStart),
[a8b27c6]660 nextExpl(nextExpl), explAlt(explAlt) {}
[452747a]661
662 ArgPack(const ArgPack& o, TypeEnvironment&& env, AssertionSet&& need, AssertionSet&& have,
[73a5cadb]663 OpenVarSet&& openVars, unsigned nextArg, Cost added )
[452747a]664 : parent(o.parent), expr(o.expr ? o.expr->clone() : nullptr), cost(o.cost + added),
665 env(move(env)), need(move(need)), have(move(have)), openVars(move(openVars)),
[a8b27c6]666 nextArg(nextArg), tupleStart(o.tupleStart), nextExpl(0), explAlt(0) {}
[73a5cadb]667
[a8b27c6]668 /// true iff this pack is in the middle of an exploded argument
669 bool hasExpl() const { return nextExpl > 0; }
[aeb75b1]670
[a8b27c6]671 /// Gets the list of exploded alternatives for this pack
672 const ExplodedActual& getExpl( const ExplodedArgs& args ) const {
673 return args[nextArg-1][explAlt];
674 }
[aeb75b1]675
676 /// Ends a tuple expression, consolidating the appropriate actuals
[403b388]677 void endTuple( const std::vector<ArgPack>& packs ) {
678 // add all expressions in tuple to list, summing cost
[aeb75b1]679 std::list<Expression*> exprs;
[403b388]680 const ArgPack* pack = this;
681 if ( expr ) { exprs.push_front( expr.release() ); }
682 while ( pack->tupleStart == 0 ) {
683 pack = &packs[pack->parent];
684 exprs.push_front( pack->expr->clone() );
685 cost += pack->cost;
[aeb75b1]686 }
[403b388]687 // reset pack to appropriate tuple
688 expr.reset( new TupleExpr( exprs ) );
689 tupleStart = pack->tupleStart - 1;
690 parent = pack->parent;
[aeb75b1]691 }
[4b6ef70]692 };
[aeb75b1]693
694 /// Instantiates an argument to match a formal, returns false if no results left
[11094d9]695 bool instantiateArgument( Type* formalType, Initializer* initializer,
[178e4ec]696 const ExplodedArgs& args, std::vector<ArgPack>& results, std::size_t& genStart,
[a8b27c6]697 const SymTab::Indexer& indexer, unsigned nTuples = 0 ) {
[aeb75b1]698 if ( TupleType* tupleType = dynamic_cast<TupleType*>( formalType ) ) {
699 // formalType is a TupleType - group actuals into a TupleExpr
[403b388]700 ++nTuples;
[aeb75b1]701 for ( Type* type : *tupleType ) {
702 // xxx - dropping initializer changes behaviour from previous, but seems correct
[452747a]703 if ( ! instantiateArgument(
704 type, nullptr, args, results, genStart, indexer, nTuples ) )
[aeb75b1]705 return false;
[403b388]706 nTuples = 0;
707 }
708 // re-consititute tuples for final generation
709 for ( auto i = genStart; i < results.size(); ++i ) {
710 results[i].endTuple( results );
[aeb75b1]711 }
712 return true;
713 } else if ( TypeInstType* ttype = Tuples::isTtype( formalType ) ) {
714 // formalType is a ttype, consumes all remaining arguments
715 // xxx - mixing default arguments with variadic??
[403b388]716
717 // completed tuples; will be spliced to end of results to finish
718 std::vector<ArgPack> finalResults{};
719
[aeb75b1]720 // iterate until all results completed
[403b388]721 std::size_t genEnd;
722 ++nTuples;
723 do {
724 genEnd = results.size();
725
[aeb75b1]726 // add another argument to results
[403b388]727 for ( std::size_t i = genStart; i < genEnd; ++i ) {
[a8b27c6]728 auto nextArg = results[i].nextArg;
[452747a]729
[62194cb]730 // use next element of exploded tuple if present
[a8b27c6]731 if ( results[i].hasExpl() ) {
732 const ExplodedActual& expl = results[i].getExpl( args );
[403b388]733
[a8b27c6]734 unsigned nextExpl = results[i].nextExpl + 1;
[62194cb]735 if ( nextExpl == expl.exprs.size() ) {
[a8b27c6]736 nextExpl = 0;
737 }
[403b388]738
739 results.emplace_back(
[178e4ec]740 i, expl.exprs[results[i].nextExpl].get(), copy(results[i].env),
741 copy(results[i].need), copy(results[i].have),
742 copy(results[i].openVars), nextArg, nTuples, Cost::zero, nextExpl,
[62194cb]743 results[i].explAlt );
[452747a]744
[403b388]745 continue;
746 }
[452747a]747
[aeb75b1]748 // finish result when out of arguments
[a8b27c6]749 if ( nextArg >= args.size() ) {
[452747a]750 ArgPack newResult{
751 results[i].env, results[i].need, results[i].have,
[403b388]752 results[i].openVars };
[a8b27c6]753 newResult.nextArg = nextArg;
[403b388]754 Type* argType;
755
[7faab5e]756 if ( nTuples > 0 || ! results[i].expr ) {
[ad51cc2]757 // first iteration or no expression to clone,
[7faab5e]758 // push empty tuple expression
[403b388]759 newResult.parent = i;
760 std::list<Expression*> emptyList;
761 newResult.expr.reset( new TupleExpr( emptyList ) );
762 argType = newResult.expr->get_result();
[aeb75b1]763 } else {
[403b388]764 // clone result to collect tuple
765 newResult.parent = results[i].parent;
766 newResult.cost = results[i].cost;
767 newResult.tupleStart = results[i].tupleStart;
768 newResult.expr.reset( results[i].expr->clone() );
769 argType = newResult.expr->get_result();
770
771 if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) {
[452747a]772 // the case where a ttype value is passed directly is special,
[403b388]773 // e.g. for argument forwarding purposes
[452747a]774 // xxx - what if passing multiple arguments, last of which is
[403b388]775 // ttype?
[452747a]776 // xxx - what would happen if unify was changed so that unifying
777 // tuple
778 // types flattened both before unifying lists? then pass in
[403b388]779 // TupleType (ttype) below.
780 --newResult.tupleStart;
781 } else {
782 // collapse leftover arguments into tuple
783 newResult.endTuple( results );
784 argType = newResult.expr->get_result();
785 }
[aeb75b1]786 }
[403b388]787
[aeb75b1]788 // check unification for ttype before adding to final
[452747a]789 if ( unify( ttype, argType, newResult.env, newResult.need, newResult.have,
[403b388]790 newResult.openVars, indexer ) ) {
791 finalResults.push_back( move(newResult) );
[aeb75b1]792 }
[452747a]793
[aeb75b1]794 continue;
795 }
796
797 // add each possible next argument
[a8b27c6]798 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
799 const ExplodedActual& expl = args[nextArg][j];
[178e4ec]800
[403b388]801 // fresh copies of parent parameters for this iteration
802 TypeEnvironment env = results[i].env;
803 OpenVarSet openVars = results[i].openVars;
804
[a8b27c6]805 env.addActual( expl.env, openVars );
[11094d9]806
[a8b27c6]807 // skip empty tuple arguments by (near-)cloning parent into next gen
[62194cb]808 if ( expl.exprs.empty() ) {
[73a5cadb]809 results.emplace_back(
[452747a]810 results[i], move(env), copy(results[i].need),
[a8b27c6]811 copy(results[i].have), move(openVars), nextArg + 1, expl.cost );
[452747a]812
[403b388]813 continue;
[4b6ef70]814 }
[11094d9]815
[403b388]816 // add new result
817 results.emplace_back(
[178e4ec]818 i, expl.exprs.front().get(), move(env), copy(results[i].need),
819 copy(results[i].have), move(openVars), nextArg + 1,
[62194cb]820 nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
[aeb75b1]821 }
822 }
823
824 // reset for next round
[403b388]825 genStart = genEnd;
826 nTuples = 0;
827 } while ( genEnd != results.size() );
828
829 // splice final results onto results
830 for ( std::size_t i = 0; i < finalResults.size(); ++i ) {
831 results.push_back( move(finalResults[i]) );
[aeb75b1]832 }
[403b388]833 return ! finalResults.empty();
[aeb75b1]834 }
[11094d9]835
[aeb75b1]836 // iterate each current subresult
[403b388]837 std::size_t genEnd = results.size();
838 for ( std::size_t i = genStart; i < genEnd; ++i ) {
[a8b27c6]839 auto nextArg = results[i].nextArg;
840
[403b388]841 // use remainder of exploded tuple if present
[a8b27c6]842 if ( results[i].hasExpl() ) {
843 const ExplodedActual& expl = results[i].getExpl( args );
[62194cb]844 Expression* expr = expl.exprs[results[i].nextExpl].get();
[452747a]845
[403b388]846 TypeEnvironment env = results[i].env;
847 AssertionSet need = results[i].need, have = results[i].have;
848 OpenVarSet openVars = results[i].openVars;
[4b6ef70]849
[62194cb]850 Type* actualType = expr->get_result();
[4b6ef70]851
852 PRINT(
853 std::cerr << "formal type is ";
854 formalType->print( std::cerr );
855 std::cerr << std::endl << "actual type is ";
856 actualType->print( std::cerr );
857 std::cerr << std::endl;
858 )
[11094d9]859
[403b388]860 if ( unify( formalType, actualType, env, need, have, openVars, indexer ) ) {
[a8b27c6]861 unsigned nextExpl = results[i].nextExpl + 1;
[62194cb]862 if ( nextExpl == expl.exprs.size() ) {
[a8b27c6]863 nextExpl = 0;
864 }
[178e4ec]865
[452747a]866 results.emplace_back(
[178e4ec]867 i, expr, move(env), move(need), move(have), move(openVars), nextArg,
[62194cb]868 nTuples, Cost::zero, nextExpl, results[i].explAlt );
[4b6ef70]869 }
870
871 continue;
[403b388]872 }
[452747a]873
[403b388]874 // use default initializers if out of arguments
[a8b27c6]875 if ( nextArg >= args.size() ) {
[aeb75b1]876 if ( ConstantExpr* cnstExpr = getDefaultValue( initializer ) ) {
877 if ( Constant* cnst = dynamic_cast<Constant*>( cnstExpr->get_constant() ) ) {
[403b388]878 TypeEnvironment env = results[i].env;
879 AssertionSet need = results[i].need, have = results[i].have;
880 OpenVarSet openVars = results[i].openVars;
881
[452747a]882 if ( unify( formalType, cnst->get_type(), env, need, have, openVars,
[403b388]883 indexer ) ) {
884 results.emplace_back(
[452747a]885 i, cnstExpr, move(env), move(need), move(have),
[a8b27c6]886 move(openVars), nextArg, nTuples );
[aeb75b1]887 }
888 }
889 }
[403b388]890
[aeb75b1]891 continue;
892 }
893
894 // Check each possible next argument
[a8b27c6]895 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
896 const ExplodedActual& expl = args[nextArg][j];
897
[403b388]898 // fresh copies of parent parameters for this iteration
899 TypeEnvironment env = results[i].env;
900 AssertionSet need = results[i].need, have = results[i].have;
901 OpenVarSet openVars = results[i].openVars;
902
[a8b27c6]903 env.addActual( expl.env, openVars );
[4b6ef70]904
[a8b27c6]905 // skip empty tuple arguments by (near-)cloning parent into next gen
[62194cb]906 if ( expl.exprs.empty() ) {
[73a5cadb]907 results.emplace_back(
[178e4ec]908 results[i], move(env), move(need), move(have), move(openVars),
[a8b27c6]909 nextArg + 1, expl.cost );
[73a5cadb]910
[4b6ef70]911 continue;
912 }
[aeb75b1]913
[4b6ef70]914 // consider only first exploded actual
[62194cb]915 Expression* expr = expl.exprs.front().get();
916 Type* actualType = expr->get_result()->clone();
[a585396]917
[4b6ef70]918 PRINT(
919 std::cerr << "formal type is ";
920 formalType->print( std::cerr );
921 std::cerr << std::endl << "actual type is ";
922 actualType->print( std::cerr );
923 std::cerr << std::endl;
924 )
[aeb75b1]925
[4b6ef70]926 // attempt to unify types
[403b388]927 if ( unify( formalType, actualType, env, need, have, openVars, indexer ) ) {
928 // add new result
929 results.emplace_back(
[178e4ec]930 i, expr, move(env), move(need), move(have), move(openVars), nextArg + 1,
[62194cb]931 nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
[4b6ef70]932 }
[aeb75b1]933 }
934 }
935
936 // reset for next parameter
[403b388]937 genStart = genEnd;
[11094d9]938
[403b388]939 return genEnd != results.size();
940 }
941
942 template<typename OutputIterator>
[13deae88]943 void AlternativeFinder::Finder::validateFunctionAlternative( const Alternative &func, ArgPack& result,
[403b388]944 const std::vector<ArgPack>& results, OutputIterator out ) {
945 ApplicationExpr *appExpr = new ApplicationExpr( func.expr->clone() );
946 // sum cost and accumulate actuals
947 std::list<Expression*>& args = appExpr->get_args();
[8a62d04]948 Cost cost = func.cost;
[403b388]949 const ArgPack* pack = &result;
950 while ( pack->expr ) {
951 args.push_front( pack->expr->clone() );
952 cost += pack->cost;
953 pack = &results[pack->parent];
954 }
955 // build and validate new alternative
956 Alternative newAlt( appExpr, result.env, cost );
957 PRINT(
958 std::cerr << "instantiate function success: " << appExpr << std::endl;
959 std::cerr << "need assertions:" << std::endl;
960 printAssertionSet( result.need, std::cerr, 8 );
961 )
962 inferParameters( result.need, result.have, newAlt, result.openVars, out );
[11094d9]963 }
[aeb75b1]964
965 template<typename OutputIterator>
[13deae88]966 void AlternativeFinder::Finder::makeFunctionAlternatives( const Alternative &func,
[a8b27c6]967 FunctionType *funcType, const ExplodedArgs &args, OutputIterator out ) {
[aeb75b1]968 OpenVarSet funcOpenVars;
969 AssertionSet funcNeed, funcHave;
[3f7e12cb]970 TypeEnvironment funcEnv( func.env );
[aeb75b1]971 makeUnifiableVars( funcType, funcOpenVars, funcNeed );
[11094d9]972 // add all type variables as open variables now so that those not used in the parameter
[aeb75b1]973 // list are still considered open.
974 funcEnv.add( funcType->get_forall() );
[11094d9]975
[53e3b4a]976 if ( targetType && ! targetType->isVoid() && ! funcType->get_returnVals().empty() ) {
[ea83e00a]977 // attempt to narrow based on expected target type
978 Type * returnType = funcType->get_returnVals().front()->get_type();
[11094d9]979 if ( ! unify( returnType, targetType, funcEnv, funcNeed, funcHave, funcOpenVars,
[aeb75b1]980 indexer ) ) {
981 // unification failed, don't pursue this function alternative
[ea83e00a]982 return;
983 }
984 }
985
[aeb75b1]986 // iteratively build matches, one parameter at a time
[403b388]987 std::vector<ArgPack> results;
988 results.push_back( ArgPack{ funcEnv, funcNeed, funcHave, funcOpenVars } );
989 std::size_t genStart = 0;
990
[aeb75b1]991 for ( DeclarationWithType* formal : funcType->get_parameters() ) {
992 ObjectDecl* obj = strict_dynamic_cast< ObjectDecl* >( formal );
[11094d9]993 if ( ! instantiateArgument(
[403b388]994 obj->get_type(), obj->get_init(), args, results, genStart, indexer ) )
[aeb75b1]995 return;
996 }
997
998 if ( funcType->get_isVarArgs() ) {
[403b388]999 // append any unused arguments to vararg pack
1000 std::size_t genEnd;
1001 do {
1002 genEnd = results.size();
1003
1004 // iterate results
1005 for ( std::size_t i = genStart; i < genEnd; ++i ) {
[a8b27c6]1006 auto nextArg = results[i].nextArg;
[452747a]1007
[403b388]1008 // use remainder of exploded tuple if present
[a8b27c6]1009 if ( results[i].hasExpl() ) {
1010 const ExplodedActual& expl = results[i].getExpl( args );
[403b388]1011
[a8b27c6]1012 unsigned nextExpl = results[i].nextExpl + 1;
[62194cb]1013 if ( nextExpl == expl.exprs.size() ) {
[a8b27c6]1014 nextExpl = 0;
1015 }
[403b388]1016
1017 results.emplace_back(
[178e4ec]1018 i, expl.exprs[results[i].nextExpl].get(), copy(results[i].env),
1019 copy(results[i].need), copy(results[i].have),
1020 copy(results[i].openVars), nextArg, 0, Cost::zero, nextExpl,
[62194cb]1021 results[i].explAlt );
[452747a]1022
[403b388]1023 continue;
1024 }
1025
1026 // finish result when out of arguments
[a8b27c6]1027 if ( nextArg >= args.size() ) {
[403b388]1028 validateFunctionAlternative( func, results[i], results, out );
[fae6f21]1029
[aeb75b1]1030 continue;
1031 }
1032
1033 // add each possible next argument
[a8b27c6]1034 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
1035 const ExplodedActual& expl = args[nextArg][j];
1036
[403b388]1037 // fresh copies of parent parameters for this iteration
1038 TypeEnvironment env = results[i].env;
1039 OpenVarSet openVars = results[i].openVars;
1040
[a8b27c6]1041 env.addActual( expl.env, openVars );
[d551d0a]1042
[a8b27c6]1043 // skip empty tuple arguments by (near-)cloning parent into next gen
[62194cb]1044 if ( expl.exprs.empty() ) {
[452747a]1045 results.emplace_back(
1046 results[i], move(env), copy(results[i].need),
[a8b27c6]1047 copy(results[i].have), move(openVars), nextArg + 1, expl.cost );
[178e4ec]1048
[403b388]1049 continue;
1050 }
[d551d0a]1051
[403b388]1052 // add new result
1053 results.emplace_back(
[178e4ec]1054 i, expl.exprs.front().get(), move(env), copy(results[i].need),
1055 copy(results[i].have), move(openVars), nextArg + 1, 0,
[62194cb]1056 expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
[aeb75b1]1057 }
1058 }
1059
[403b388]1060 genStart = genEnd;
1061 } while ( genEnd != results.size() );
[aeb75b1]1062 } else {
1063 // filter out results that don't use all the arguments
[403b388]1064 for ( std::size_t i = genStart; i < results.size(); ++i ) {
1065 ArgPack& result = results[i];
[a8b27c6]1066 if ( ! result.hasExpl() && result.nextArg >= args.size() ) {
[403b388]1067 validateFunctionAlternative( func, result, results, out );
[aeb75b1]1068 }
1069 }
1070 }
[d9a0e76]1071 }
1072
[13deae88]1073 void AlternativeFinder::Finder::postvisit( UntypedExpr *untypedExpr ) {
[6ccfb7f]1074 AlternativeFinder funcFinder( indexer, env );
[a32b204]1075 funcFinder.findWithAdjustment( untypedExpr->get_function() );
[6ccfb7f]1076 // if there are no function alternatives, then proceeding is a waste of time.
1077 if ( funcFinder.alternatives.empty() ) return;
1078
[aeb75b1]1079 std::vector< AlternativeFinder > argAlternatives;
[13deae88]1080 altFinder.findSubExprs( untypedExpr->begin_args(), untypedExpr->end_args(),
[aeb75b1]1081 back_inserter( argAlternatives ) );
[d9a0e76]1082
[5af62f1]1083 // take care of possible tuple assignments
1084 // if not tuple assignment, assignment is taken care of as a normal function call
[13deae88]1085 Tuples::handleTupleAssignment( altFinder, untypedExpr, argAlternatives );
[c43c171]1086
[6ccfb7f]1087 // find function operators
[4e66a18]1088 static NameExpr *opExpr = new NameExpr( "?()" );
[6ccfb7f]1089 AlternativeFinder funcOpFinder( indexer, env );
[4e66a18]1090 // it's ok if there aren't any defined function ops
1091 funcOpFinder.maybeFind( opExpr);
[6ccfb7f]1092 PRINT(
1093 std::cerr << "known function ops:" << std::endl;
[50377a4]1094 printAlts( funcOpFinder.alternatives, std::cerr, 1 );
[6ccfb7f]1095 )
1096
[a8b27c6]1097 // pre-explode arguments
1098 ExplodedArgs argExpansions;
1099 argExpansions.reserve( argAlternatives.size() );
1100
1101 for ( const AlternativeFinder& arg : argAlternatives ) {
1102 argExpansions.emplace_back();
1103 auto& argE = argExpansions.back();
1104 argE.reserve( arg.alternatives.size() );
[178e4ec]1105
[a8b27c6]1106 for ( const Alternative& actual : arg ) {
1107 argE.emplace_back( actual, indexer );
1108 }
1109 }
1110
[a32b204]1111 AltList candidates;
[91b8a17]1112 SemanticError errors;
[b1bead1]1113 for ( AltList::iterator func = funcFinder.alternatives.begin(); func != funcFinder.alternatives.end(); ++func ) {
[91b8a17]1114 try {
1115 PRINT(
1116 std::cerr << "working on alternative: " << std::endl;
1117 func->print( std::cerr, 8 );
1118 )
1119 // check if the type is pointer to function
[b1bead1]1120 if ( PointerType *pointer = dynamic_cast< PointerType* >( func->expr->get_result()->stripReferences() ) ) {
[91b8a17]1121 if ( FunctionType *function = dynamic_cast< FunctionType* >( pointer->get_base() ) ) {
[326338ae]1122 Alternative newFunc( *func );
1123 referenceToRvalueConversion( newFunc.expr );
[a8b27c6]1124 makeFunctionAlternatives( newFunc, function, argExpansions,
[aeb75b1]1125 std::back_inserter( candidates ) );
[b1bead1]1126 }
1127 } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr->get_result()->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer)
1128 EqvClass eqvClass;
1129 if ( func->env.lookup( typeInst->get_name(), eqvClass ) && eqvClass.type ) {
1130 if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass.type ) ) {
[326338ae]1131 Alternative newFunc( *func );
1132 referenceToRvalueConversion( newFunc.expr );
[a8b27c6]1133 makeFunctionAlternatives( newFunc, function, argExpansions,
[aeb75b1]1134 std::back_inserter( candidates ) );
[a32b204]1135 } // if
1136 } // if
[11094d9]1137 }
[91b8a17]1138 } catch ( SemanticError &e ) {
1139 errors.append( e );
1140 }
[a32b204]1141 } // for
1142
[aeb75b1]1143 // try each function operator ?() with each function alternative
1144 if ( ! funcOpFinder.alternatives.empty() ) {
[a8b27c6]1145 // add exploded function alternatives to front of argument list
1146 std::vector<ExplodedActual> funcE;
1147 funcE.reserve( funcFinder.alternatives.size() );
1148 for ( const Alternative& actual : funcFinder ) {
1149 funcE.emplace_back( actual, indexer );
1150 }
1151 argExpansions.insert( argExpansions.begin(), move(funcE) );
[aeb75b1]1152
1153 for ( AltList::iterator funcOp = funcOpFinder.alternatives.begin();
1154 funcOp != funcOpFinder.alternatives.end(); ++funcOp ) {
1155 try {
1156 // check if type is a pointer to function
[11094d9]1157 if ( PointerType* pointer = dynamic_cast<PointerType*>(
[aeb75b1]1158 funcOp->expr->get_result()->stripReferences() ) ) {
[11094d9]1159 if ( FunctionType* function =
[aeb75b1]1160 dynamic_cast<FunctionType*>( pointer->get_base() ) ) {
1161 Alternative newFunc( *funcOp );
1162 referenceToRvalueConversion( newFunc.expr );
[a8b27c6]1163 makeFunctionAlternatives( newFunc, function, argExpansions,
[aeb75b1]1164 std::back_inserter( candidates ) );
1165 }
1166 }
1167 } catch ( SemanticError &e ) {
1168 errors.append( e );
1169 }
1170 }
1171 }
1172
[91b8a17]1173 // Implement SFINAE; resolution errors are only errors if there aren't any non-erroneous resolutions
1174 if ( candidates.empty() && ! errors.isEmpty() ) { throw errors; }
1175
[4b0f997]1176 // compute conversionsion costs
[bd4f2e9]1177 for ( Alternative& withFunc : candidates ) {
1178 Cost cvtCost = computeApplicationConversionCost( withFunc, indexer );
[a32b204]1179
1180 PRINT(
[bd4f2e9]1181 ApplicationExpr *appExpr = strict_dynamic_cast< ApplicationExpr* >( withFunc.expr );
[e3e16bc]1182 PointerType *pointer = strict_dynamic_cast< PointerType* >( appExpr->get_function()->get_result() );
1183 FunctionType *function = strict_dynamic_cast< FunctionType* >( pointer->get_base() );
[a61ad31]1184 std::cerr << "Case +++++++++++++ " << appExpr->get_function() << std::endl;
[6ed1d4b]1185 std::cerr << "formals are:" << std::endl;
1186 printAll( function->get_parameters(), std::cerr, 8 );
1187 std::cerr << "actuals are:" << std::endl;
1188 printAll( appExpr->get_args(), std::cerr, 8 );
1189 std::cerr << "bindings are:" << std::endl;
[bd4f2e9]1190 withFunc.env.print( std::cerr, 8 );
[6ed1d4b]1191 std::cerr << "cost of conversion is:" << cvtCost << std::endl;
[7c64920]1192 )
1193 if ( cvtCost != Cost::infinity ) {
[bd4f2e9]1194 withFunc.cvtCost = cvtCost;
1195 alternatives.push_back( withFunc );
[7c64920]1196 } // if
[a32b204]1197 } // for
[4b0f997]1198
[bd4f2e9]1199 candidates = move(alternatives);
[a32b204]1200
[11094d9]1201 // use a new list so that alternatives are not examined by addAnonConversions twice.
1202 AltList winners;
1203 findMinCost( candidates.begin(), candidates.end(), std::back_inserter( winners ) );
[ea83e00a]1204
[452747a]1205 // function may return struct or union value, in which case we need to add alternatives
1206 // for implicitconversions to each of the anonymous members, must happen after findMinCost
[bd4f2e9]1207 // since anon conversions are never the cheapest expression
[11094d9]1208 for ( const Alternative & alt : winners ) {
[ca946a4]1209 addAnonConversions( alt );
1210 }
[bd4f2e9]1211 spliceBegin( alternatives, winners );
[ca946a4]1212
[ea83e00a]1213 if ( alternatives.empty() && targetType && ! targetType->isVoid() ) {
1214 // xxx - this is a temporary hack. If resolution is unsuccessful with a target type, try again without a
1215 // target type, since it will sometimes succeed when it wouldn't easily with target type binding. For example,
1216 // forall( otype T ) lvalue T ?[?]( T *, ptrdiff_t );
1217 // const char * x = "hello world";
1218 // unsigned char ch = x[0];
1219 // Fails with simple return type binding. First, T is bound to unsigned char, then (x: const char *) is unified
1220 // with unsigned char *, which fails because pointer base types must be unified exactly. The new resolver should
1221 // fix this issue in a more robust way.
1222 targetType = nullptr;
[13deae88]1223 postvisit( untypedExpr );
[ea83e00a]1224 }
[a32b204]1225 }
1226
1227 bool isLvalue( Expression *expr ) {
[906e24d]1228 // xxx - recurse into tuples?
[d29fa5f]1229 return expr->result && ( expr->get_result()->get_lvalue() || dynamic_cast< ReferenceType * >( expr->get_result() ) );
[a32b204]1230 }
1231
[13deae88]1232 void AlternativeFinder::Finder::postvisit( AddressExpr *addressExpr ) {
[a32b204]1233 AlternativeFinder finder( indexer, env );
1234 finder.find( addressExpr->get_arg() );
[bd4f2e9]1235 for ( Alternative& alt : finder.alternatives ) {
1236 if ( isLvalue( alt.expr ) ) {
[452747a]1237 alternatives.push_back(
[bd4f2e9]1238 Alternative{ new AddressExpr( alt.expr->clone() ), alt.env, alt.cost } );
[a32b204]1239 } // if
1240 } // for
1241 }
1242
[13deae88]1243 void AlternativeFinder::Finder::postvisit( LabelAddressExpr * expr ) {
[bd4f2e9]1244 alternatives.push_back( Alternative{ expr->clone(), env, Cost::zero } );
[5809461]1245 }
1246
[62423350]1247 Expression * restructureCast( Expression * argExpr, Type * toType ) {
[e6cee92]1248 if ( argExpr->get_result()->size() > 1 && ! toType->isVoid() && ! dynamic_cast<ReferenceType *>( toType ) ) {
1249 // Argument expression is a tuple and the target type is not void and not a reference type.
1250 // Cast each member of the tuple to its corresponding target type, producing the tuple of those
1251 // cast expressions. If there are more components of the tuple than components in the target type,
1252 // then excess components do not come out in the result expression (but UniqueExprs ensure that
1253 // side effects will still be done).
[5ccb10d]1254 if ( Tuples::maybeImpureIgnoreUnique( argExpr ) ) {
[62423350]1255 // expressions which may contain side effects require a single unique instance of the expression.
1256 argExpr = new UniqueExpr( argExpr );
1257 }
1258 std::list< Expression * > componentExprs;
1259 for ( unsigned int i = 0; i < toType->size(); i++ ) {
1260 // cast each component
1261 TupleIndexExpr * idx = new TupleIndexExpr( argExpr->clone(), i );
1262 componentExprs.push_back( restructureCast( idx, toType->getComponent( i ) ) );
1263 }
1264 delete argExpr;
1265 assert( componentExprs.size() > 0 );
1266 // produce the tuple of casts
1267 return new TupleExpr( componentExprs );
1268 } else {
1269 // handle normally
1270 return new CastExpr( argExpr, toType->clone() );
1271 }
1272 }
1273
[13deae88]1274 void AlternativeFinder::Finder::postvisit( CastExpr *castExpr ) {
[906e24d]1275 Type *& toType = castExpr->get_result();
[7933351]1276 assert( toType );
[906e24d]1277 toType = resolveTypeof( toType, indexer );
1278 SymTab::validateType( toType, &indexer );
1279 adjustExprType( toType, env, indexer );
[a32b204]1280
1281 AlternativeFinder finder( indexer, env );
[7933351]1282 finder.targetType = toType;
[a32b204]1283 finder.findWithAdjustment( castExpr->get_arg() );
1284
1285 AltList candidates;
[452747a]1286 for ( Alternative & alt : finder.alternatives ) {
[a32b204]1287 AssertionSet needAssertions, haveAssertions;
1288 OpenVarSet openVars;
1289
1290 // It's possible that a cast can throw away some values in a multiply-valued expression. (An example is a
1291 // cast-to-void, which casts from one value to zero.) Figure out the prefix of the subexpression results
1292 // that are cast directly. The candidate is invalid if it has fewer results than there are types to cast
1293 // to.
[bd4f2e9]1294 int discardedValues = alt.expr->get_result()->size() - castExpr->get_result()->size();
[a32b204]1295 if ( discardedValues < 0 ) continue;
[7933351]1296 // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
1297 // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
[adcdd2f]1298 // unification run for side-effects
[452747a]1299 unify( castExpr->get_result(), alt.expr->get_result(), alt.env, needAssertions,
[bd4f2e9]1300 haveAssertions, openVars, indexer );
[452747a]1301 Cost thisCost = castCost( alt.expr->get_result(), castExpr->get_result(), indexer,
[bd4f2e9]1302 alt.env );
[7e4c4f4]1303 PRINT(
1304 std::cerr << "working on cast with result: " << castExpr->result << std::endl;
[452747a]1305 std::cerr << "and expr type: " << alt.expr->result << std::endl;
1306 std::cerr << "env: " << alt.env << std::endl;
[7e4c4f4]1307 )
[a32b204]1308 if ( thisCost != Cost::infinity ) {
[7e4c4f4]1309 PRINT(
1310 std::cerr << "has finite cost." << std::endl;
1311 )
[a32b204]1312 // count one safe conversion for each value that is thrown away
[89be1c68]1313 thisCost.incSafe( discardedValues );
[452747a]1314 Alternative newAlt( restructureCast( alt.expr->clone(), toType ), alt.env,
[bd4f2e9]1315 alt.cost, thisCost );
[452747a]1316 inferParameters( needAssertions, haveAssertions, newAlt, openVars,
[bd4f2e9]1317 back_inserter( candidates ) );
[a32b204]1318 } // if
1319 } // for
1320
1321 // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the
1322 // cvtCost member to the cost member (since the old cost is now irrelevant). Thus, calling findMinCost twice
1323 // selects first based on argument cost, then on conversion cost.
1324 AltList minArgCost;
1325 findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) );
1326 findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );
1327 }
1328
[13deae88]1329 void AlternativeFinder::Finder::postvisit( VirtualCastExpr * castExpr ) {
[a5f0529]1330 assertf( castExpr->get_result(), "Implicate virtual cast targets not yet supported." );
1331 AlternativeFinder finder( indexer, env );
1332 // don't prune here, since it's guaranteed all alternatives will have the same type
[4e66a18]1333 finder.findWithoutPrune( castExpr->get_arg() );
[a5f0529]1334 for ( Alternative & alt : finder.alternatives ) {
1335 alternatives.push_back( Alternative(
1336 new VirtualCastExpr( alt.expr->clone(), castExpr->get_result()->clone() ),
1337 alt.env, alt.cost ) );
1338 }
1339 }
1340
[13deae88]1341 void AlternativeFinder::Finder::postvisit( UntypedMemberExpr *memberExpr ) {
[a32b204]1342 AlternativeFinder funcFinder( indexer, env );
1343 funcFinder.findWithAdjustment( memberExpr->get_aggregate() );
1344 for ( AltList::const_iterator agg = funcFinder.alternatives.begin(); agg != funcFinder.alternatives.end(); ++agg ) {
[a61ad31]1345 // 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
1346 std::unique_ptr<Expression> aggrExpr( agg->expr->clone() );
1347 Type * aggrType = aggrExpr->get_result();
1348 if ( dynamic_cast< ReferenceType * >( aggrType ) ) {
1349 aggrType = aggrType->stripReferences();
1350 aggrExpr.reset( new CastExpr( aggrExpr.release(), aggrType->clone() ) );
1351 }
1352 // find member of the given type
1353 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) {
1354 addAggMembers( structInst, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() );
1355 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) {
1356 addAggMembers( unionInst, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() );
1357 } else if ( TupleType * tupleType = dynamic_cast< TupleType * >( aggrExpr->get_result() ) ) {
1358 addTupleMembers( tupleType, aggrExpr.get(), agg->cost, agg->env, memberExpr->get_member() );
[a32b204]1359 } // if
1360 } // for
1361 }
1362
[13deae88]1363 void AlternativeFinder::Finder::postvisit( MemberExpr *memberExpr ) {
[a32b204]1364 alternatives.push_back( Alternative( memberExpr->clone(), env, Cost::zero ) );
1365 }
1366
[13deae88]1367 void AlternativeFinder::Finder::postvisit( NameExpr *nameExpr ) {
[a40d503]1368 std::list< SymTab::Indexer::IdData > declList;
[490ff5c3]1369 indexer.lookupId( nameExpr->name, declList );
1370 PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
[a40d503]1371 for ( auto & data : declList ) {
1372 Expression * newExpr = data.combine();
1373 // xxx - add in extra cost for with-statement exprs?
1374 alternatives.push_back( Alternative( newExpr, env, Cost::zero ) );
[0f19d763]1375 PRINT(
1376 std::cerr << "decl is ";
[a40d503]1377 data.id->print( std::cerr );
[0f19d763]1378 std::cerr << std::endl;
1379 std::cerr << "newExpr is ";
[a40d503]1380 newExpr->print( std::cerr );
[0f19d763]1381 std::cerr << std::endl;
[7c64920]1382 )
[0f19d763]1383 renameTypes( alternatives.back().expr );
[4b0f997]1384 addAnonConversions( alternatives.back() ); // add anonymous member interpretations whenever an aggregate value type is seen as a name expression.
[0f19d763]1385 } // for
[a32b204]1386 }
1387
[13deae88]1388 void AlternativeFinder::Finder::postvisit( VariableExpr *variableExpr ) {
[85517ddb]1389 // not sufficient to clone here, because variable's type may have changed
1390 // since the VariableExpr was originally created.
[490ff5c3]1391 alternatives.push_back( Alternative( new VariableExpr( variableExpr->var ), env, Cost::zero ) );
[a32b204]1392 }
1393
[13deae88]1394 void AlternativeFinder::Finder::postvisit( ConstantExpr *constantExpr ) {
[a32b204]1395 alternatives.push_back( Alternative( constantExpr->clone(), env, Cost::zero ) );
1396 }
1397
[13deae88]1398 void AlternativeFinder::Finder::postvisit( SizeofExpr *sizeofExpr ) {
[a32b204]1399 if ( sizeofExpr->get_isType() ) {
[322b97e]1400 Type * newType = sizeofExpr->get_type()->clone();
1401 alternatives.push_back( Alternative( new SizeofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
[a32b204]1402 } else {
1403 // find all alternatives for the argument to sizeof
1404 AlternativeFinder finder( indexer, env );
1405 finder.find( sizeofExpr->get_expr() );
1406 // find the lowest cost alternative among the alternatives, otherwise ambiguous
1407 AltList winners;
1408 findMinCost( finder.alternatives.begin(), finder.alternatives.end(), back_inserter( winners ) );
1409 if ( winners.size() != 1 ) {
[d55d7a6]1410 throw SemanticError( sizeofExpr->get_expr(), "Ambiguous expression in sizeof operand: " );
[a32b204]1411 } // if
1412 // return the lowest cost alternative for the argument
1413 Alternative &choice = winners.front();
[b37dba0]1414 referenceToRvalueConversion( choice.expr );
[a32b204]1415 alternatives.push_back( Alternative( new SizeofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
[47534159]1416 } // if
1417 }
1418
[13deae88]1419 void AlternativeFinder::Finder::postvisit( AlignofExpr *alignofExpr ) {
[47534159]1420 if ( alignofExpr->get_isType() ) {
[322b97e]1421 Type * newType = alignofExpr->get_type()->clone();
1422 alternatives.push_back( Alternative( new AlignofExpr( resolveTypeof( newType, indexer ) ), env, Cost::zero ) );
[47534159]1423 } else {
1424 // find all alternatives for the argument to sizeof
1425 AlternativeFinder finder( indexer, env );
1426 finder.find( alignofExpr->get_expr() );
1427 // find the lowest cost alternative among the alternatives, otherwise ambiguous
1428 AltList winners;
1429 findMinCost( finder.alternatives.begin(), finder.alternatives.end(), back_inserter( winners ) );
1430 if ( winners.size() != 1 ) {
[d55d7a6]1431 throw SemanticError( alignofExpr->get_expr(), "Ambiguous expression in alignof operand: " );
[47534159]1432 } // if
1433 // return the lowest cost alternative for the argument
1434 Alternative &choice = winners.front();
[b37dba0]1435 referenceToRvalueConversion( choice.expr );
[47534159]1436 alternatives.push_back( Alternative( new AlignofExpr( choice.expr->clone() ), choice.env, Cost::zero ) );
[a32b204]1437 } // if
1438 }
1439
[2a4b088]1440 template< typename StructOrUnionType >
[13deae88]1441 void AlternativeFinder::Finder::addOffsetof( StructOrUnionType *aggInst, const std::string &name ) {
[2a4b088]1442 std::list< Declaration* > members;
1443 aggInst->lookup( name, members );
1444 for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) {
1445 if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) {
[79970ed]1446 alternatives.push_back( Alternative( new OffsetofExpr( aggInst->clone(), dwt ), env, Cost::zero ) );
[2a4b088]1447 renameTypes( alternatives.back().expr );
1448 } else {
1449 assert( false );
1450 }
1451 }
1452 }
[6ed1d4b]1453
[13deae88]1454 void AlternativeFinder::Finder::postvisit( UntypedOffsetofExpr *offsetofExpr ) {
[2a4b088]1455 AlternativeFinder funcFinder( indexer, env );
[85517ddb]1456 // xxx - resolveTypeof?
[2a4b088]1457 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( offsetofExpr->get_type() ) ) {
[490ff5c3]1458 addOffsetof( structInst, offsetofExpr->member );
[2a4b088]1459 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( offsetofExpr->get_type() ) ) {
[490ff5c3]1460 addOffsetof( unionInst, offsetofExpr->member );
[2a4b088]1461 }
1462 }
[6ed1d4b]1463
[13deae88]1464 void AlternativeFinder::Finder::postvisit( OffsetofExpr *offsetofExpr ) {
[25a054f]1465 alternatives.push_back( Alternative( offsetofExpr->clone(), env, Cost::zero ) );
[afc1045]1466 }
1467
[13deae88]1468 void AlternativeFinder::Finder::postvisit( OffsetPackExpr *offsetPackExpr ) {
[afc1045]1469 alternatives.push_back( Alternative( offsetPackExpr->clone(), env, Cost::zero ) );
[25a054f]1470 }
1471
[a40d503]1472 namespace {
1473 void resolveAttr( SymTab::Indexer::IdData data, FunctionType *function, Type *argType, const TypeEnvironment &env, AlternativeFinder & finder ) {
1474 // assume no polymorphism
1475 // assume no implicit conversions
1476 assert( function->get_parameters().size() == 1 );
1477 PRINT(
1478 std::cerr << "resolvAttr: funcDecl is ";
1479 data.id->print( std::cerr );
1480 std::cerr << " argType is ";
1481 argType->print( std::cerr );
1482 std::cerr << std::endl;
1483 )
1484 const SymTab::Indexer & indexer = finder.get_indexer();
1485 AltList & alternatives = finder.get_alternatives();
1486 if ( typesCompatibleIgnoreQualifiers( argType, function->get_parameters().front()->get_type(), indexer, env ) ) {
1487 alternatives.push_back( Alternative( new AttrExpr( data.combine(), argType->clone() ), env, Cost::zero ) );
1488 for ( DeclarationWithType * retVal : function->returnVals ) {
1489 alternatives.back().expr->result = retVal->get_type()->clone();
1490 } // for
1491 } // if
1492 }
[a32b204]1493 }
1494
[13deae88]1495 void AlternativeFinder::Finder::postvisit( AttrExpr *attrExpr ) {
[a32b204]1496 // assume no 'pointer-to-attribute'
1497 NameExpr *nameExpr = dynamic_cast< NameExpr* >( attrExpr->get_attr() );
1498 assert( nameExpr );
[a40d503]1499 std::list< SymTab::Indexer::IdData > attrList;
[a32b204]1500 indexer.lookupId( nameExpr->get_name(), attrList );
1501 if ( attrExpr->get_isType() || attrExpr->get_expr() ) {
[a40d503]1502 for ( auto & data : attrList ) {
1503 DeclarationWithType * id = data.id;
[a32b204]1504 // check if the type is function
[a40d503]1505 if ( FunctionType *function = dynamic_cast< FunctionType* >( id->get_type() ) ) {
[a32b204]1506 // assume exactly one parameter
1507 if ( function->get_parameters().size() == 1 ) {
1508 if ( attrExpr->get_isType() ) {
[13deae88]1509 resolveAttr( data, function, attrExpr->get_type(), env, altFinder);
[a32b204]1510 } else {
1511 AlternativeFinder finder( indexer, env );
1512 finder.find( attrExpr->get_expr() );
1513 for ( AltList::iterator choice = finder.alternatives.begin(); choice != finder.alternatives.end(); ++choice ) {
[906e24d]1514 if ( choice->expr->get_result()->size() == 1 ) {
[13deae88]1515 resolveAttr(data, function, choice->expr->get_result(), choice->env, altFinder );
[a32b204]1516 } // fi
1517 } // for
1518 } // if
1519 } // if
1520 } // if
1521 } // for
1522 } else {
[a40d503]1523 for ( auto & data : attrList ) {
1524 alternatives.push_back( Alternative( data.combine(), env, Cost::zero ) );
[a32b204]1525 renameTypes( alternatives.back().expr );
1526 } // for
1527 } // if
1528 }
1529
[13deae88]1530 void AlternativeFinder::Finder::postvisit( LogicalExpr *logicalExpr ) {
[a32b204]1531 AlternativeFinder firstFinder( indexer, env );
1532 firstFinder.findWithAdjustment( logicalExpr->get_arg1() );
[fee651f]1533 if ( firstFinder.alternatives.empty() ) return;
1534 AlternativeFinder secondFinder( indexer, env );
1535 secondFinder.findWithAdjustment( logicalExpr->get_arg2() );
1536 if ( secondFinder.alternatives.empty() ) return;
[490ff5c3]1537 for ( const Alternative & first : firstFinder.alternatives ) {
1538 for ( const Alternative & second : secondFinder.alternatives ) {
[fee651f]1539 TypeEnvironment compositeEnv;
[490ff5c3]1540 compositeEnv.simpleCombine( first.env );
1541 compositeEnv.simpleCombine( second.env );
[fee651f]1542
[490ff5c3]1543 LogicalExpr *newExpr = new LogicalExpr( first.expr->clone(), second.expr->clone(), logicalExpr->get_isAnd() );
1544 alternatives.push_back( Alternative( newExpr, compositeEnv, first.cost + second.cost ) );
[d9a0e76]1545 }
1546 }
1547 }
[51b73452]1548
[13deae88]1549 void AlternativeFinder::Finder::postvisit( ConditionalExpr *conditionalExpr ) {
[32b8144]1550 // find alternatives for condition
[a32b204]1551 AlternativeFinder firstFinder( indexer, env );
[624b722d]1552 firstFinder.findWithAdjustment( conditionalExpr->arg1 );
[ebcb7ba]1553 if ( firstFinder.alternatives.empty() ) return;
1554 // find alternatives for true expression
1555 AlternativeFinder secondFinder( indexer, env );
[624b722d]1556 secondFinder.findWithAdjustment( conditionalExpr->arg2 );
[ebcb7ba]1557 if ( secondFinder.alternatives.empty() ) return;
1558 // find alterantives for false expression
1559 AlternativeFinder thirdFinder( indexer, env );
[624b722d]1560 thirdFinder.findWithAdjustment( conditionalExpr->arg3 );
[ebcb7ba]1561 if ( thirdFinder.alternatives.empty() ) return;
[624b722d]1562 for ( const Alternative & first : firstFinder.alternatives ) {
1563 for ( const Alternative & second : secondFinder.alternatives ) {
1564 for ( const Alternative & third : thirdFinder.alternatives ) {
[ebcb7ba]1565 TypeEnvironment compositeEnv;
[624b722d]1566 compositeEnv.simpleCombine( first.env );
1567 compositeEnv.simpleCombine( second.env );
1568 compositeEnv.simpleCombine( third.env );
[ebcb7ba]1569
[32b8144]1570 // unify true and false types, then infer parameters to produce new alternatives
[a32b204]1571 OpenVarSet openVars;
1572 AssertionSet needAssertions, haveAssertions;
[624b722d]1573 Alternative newAlt( 0, compositeEnv, first.cost + second.cost + third.cost );
[668e971a]1574 Type* commonType = nullptr;
[624b722d]1575 if ( unify( second.expr->result, third.expr->result, newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
1576 ConditionalExpr *newExpr = new ConditionalExpr( first.expr->clone(), second.expr->clone(), third.expr->clone() );
1577 newExpr->result = commonType ? commonType : second.expr->result->clone();
[ddf8a29]1578 // convert both options to the conditional result type
1579 newAlt.cost += computeExpressionConversionCost( newExpr->arg2, newExpr->result, indexer, newAlt.env );
1580 newAlt.cost += computeExpressionConversionCost( newExpr->arg3, newExpr->result, indexer, newAlt.env );
[a32b204]1581 newAlt.expr = newExpr;
1582 inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
1583 } // if
1584 } // for
1585 } // for
1586 } // for
1587 }
1588
[13deae88]1589 void AlternativeFinder::Finder::postvisit( CommaExpr *commaExpr ) {
[a32b204]1590 TypeEnvironment newEnv( env );
1591 Expression *newFirstArg = resolveInVoidContext( commaExpr->get_arg1(), indexer, newEnv );
1592 AlternativeFinder secondFinder( indexer, newEnv );
1593 secondFinder.findWithAdjustment( commaExpr->get_arg2() );
[490ff5c3]1594 for ( const Alternative & alt : secondFinder.alternatives ) {
1595 alternatives.push_back( Alternative( new CommaExpr( newFirstArg->clone(), alt.expr->clone() ), alt.env, alt.cost ) );
[a32b204]1596 } // for
1597 delete newFirstArg;
1598 }
1599
[13deae88]1600 void AlternativeFinder::Finder::postvisit( RangeExpr * rangeExpr ) {
[32b8144]1601 // resolve low and high, accept alternatives whose low and high types unify
1602 AlternativeFinder firstFinder( indexer, env );
[490ff5c3]1603 firstFinder.findWithAdjustment( rangeExpr->low );
[fee651f]1604 if ( firstFinder.alternatives.empty() ) return;
1605 AlternativeFinder secondFinder( indexer, env );
[490ff5c3]1606 secondFinder.findWithAdjustment( rangeExpr->high );
[fee651f]1607 if ( secondFinder.alternatives.empty() ) return;
[490ff5c3]1608 for ( const Alternative & first : firstFinder.alternatives ) {
1609 for ( const Alternative & second : secondFinder.alternatives ) {
[fee651f]1610 TypeEnvironment compositeEnv;
[490ff5c3]1611 compositeEnv.simpleCombine( first.env );
1612 compositeEnv.simpleCombine( second.env );
[32b8144]1613 OpenVarSet openVars;
1614 AssertionSet needAssertions, haveAssertions;
[490ff5c3]1615 Alternative newAlt( 0, compositeEnv, first.cost + second.cost );
[32b8144]1616 Type* commonType = nullptr;
[490ff5c3]1617 if ( unify( first.expr->result, second.expr->result, newAlt.env, needAssertions, haveAssertions, openVars, indexer, commonType ) ) {
1618 RangeExpr * newExpr = new RangeExpr( first.expr->clone(), second.expr->clone() );
1619 newExpr->result = commonType ? commonType : first.expr->result->clone();
[32b8144]1620 newAlt.expr = newExpr;
1621 inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( alternatives ) );
1622 } // if
1623 } // for
1624 } // for
1625 }
1626
[13deae88]1627 void AlternativeFinder::Finder::postvisit( UntypedTupleExpr *tupleExpr ) {
[bd4f2e9]1628 std::vector< AlternativeFinder > subExprAlternatives;
[13deae88]1629 altFinder.findSubExprs( tupleExpr->get_exprs().begin(), tupleExpr->get_exprs().end(),
[bd4f2e9]1630 back_inserter( subExprAlternatives ) );
1631 std::vector< AltList > possibilities;
[452747a]1632 combos( subExprAlternatives.begin(), subExprAlternatives.end(),
[bd4f2e9]1633 back_inserter( possibilities ) );
1634 for ( const AltList& alts : possibilities ) {
[907eccb]1635 std::list< Expression * > exprs;
[bd4f2e9]1636 makeExprList( alts, exprs );
[a32b204]1637
1638 TypeEnvironment compositeEnv;
[bd4f2e9]1639 simpleCombineEnvironments( alts.begin(), alts.end(), compositeEnv );
[452747a]1640 alternatives.push_back(
[bd4f2e9]1641 Alternative{ new TupleExpr( exprs ), compositeEnv, sumCost( alts ) } );
[a32b204]1642 } // for
[d9a0e76]1643 }
[dc2e7e0]1644
[13deae88]1645 void AlternativeFinder::Finder::postvisit( TupleExpr *tupleExpr ) {
[907eccb]1646 alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
1647 }
1648
[13deae88]1649 void AlternativeFinder::Finder::postvisit( ImplicitCopyCtorExpr * impCpCtorExpr ) {
[dc2e7e0]1650 alternatives.push_back( Alternative( impCpCtorExpr->clone(), env, Cost::zero ) );
1651 }
[b6fe7e6]1652
[13deae88]1653 void AlternativeFinder::Finder::postvisit( ConstructorExpr * ctorExpr ) {
[b6fe7e6]1654 AlternativeFinder finder( indexer, env );
1655 // don't prune here, since it's guaranteed all alternatives will have the same type
1656 // (giving the alternatives different types is half of the point of ConstructorExpr nodes)
[4e66a18]1657 finder.findWithoutPrune( ctorExpr->get_callExpr() );
[b6fe7e6]1658 for ( Alternative & alt : finder.alternatives ) {
1659 alternatives.push_back( Alternative( new ConstructorExpr( alt.expr->clone() ), alt.env, alt.cost ) );
1660 }
1661 }
[8f7cea1]1662
[13deae88]1663 void AlternativeFinder::Finder::postvisit( TupleIndexExpr *tupleExpr ) {
[8f7cea1]1664 alternatives.push_back( Alternative( tupleExpr->clone(), env, Cost::zero ) );
1665 }
[aa8f9df]1666
[13deae88]1667 void AlternativeFinder::Finder::postvisit( TupleAssignExpr *tupleAssignExpr ) {
[aa8f9df]1668 alternatives.push_back( Alternative( tupleAssignExpr->clone(), env, Cost::zero ) );
1669 }
[bf32bb8]1670
[13deae88]1671 void AlternativeFinder::Finder::postvisit( UniqueExpr *unqExpr ) {
[bf32bb8]1672 AlternativeFinder finder( indexer, env );
1673 finder.findWithAdjustment( unqExpr->get_expr() );
1674 for ( Alternative & alt : finder.alternatives ) {
[141b786]1675 // ensure that the id is passed on to the UniqueExpr alternative so that the expressions are "linked"
[77971f6]1676 UniqueExpr * newUnqExpr = new UniqueExpr( alt.expr->clone(), unqExpr->get_id() );
[141b786]1677 alternatives.push_back( Alternative( newUnqExpr, alt.env, alt.cost ) );
[bf32bb8]1678 }
1679 }
1680
[13deae88]1681 void AlternativeFinder::Finder::postvisit( StmtExpr *stmtExpr ) {
[722617d]1682 StmtExpr * newStmtExpr = stmtExpr->clone();
1683 ResolvExpr::resolveStmtExpr( newStmtExpr, indexer );
1684 // xxx - this env is almost certainly wrong, and needs to somehow contain the combined environments from all of the statements in the stmtExpr...
1685 alternatives.push_back( Alternative( newStmtExpr, env, Cost::zero ) );
1686 }
1687
[13deae88]1688 void AlternativeFinder::Finder::postvisit( UntypedInitExpr *initExpr ) {
[62423350]1689 // handle each option like a cast
[e4d829b]1690 AltList candidates;
[13deae88]1691 PRINT(
1692 std::cerr << "untyped init expr: " << initExpr << std::endl;
1693 )
[e4d829b]1694 // O(N^2) checks of d-types with e-types
[62423350]1695 for ( InitAlternative & initAlt : initExpr->get_initAlts() ) {
[228099e]1696 Type * toType = resolveTypeof( initAlt.type->clone(), indexer );
[62423350]1697 SymTab::validateType( toType, &indexer );
1698 adjustExprType( toType, env, indexer );
1699 // Ideally the call to findWithAdjustment could be moved out of the loop, but unfortunately it currently has to occur inside or else
1700 // polymorphic return types are not properly bound to the initialization type, since return type variables are only open for the duration of resolving
1701 // the UntypedExpr. This is only actually an issue in initialization contexts that allow more than one possible initialization type, but it is still suboptimal.
1702 AlternativeFinder finder( indexer, env );
1703 finder.targetType = toType;
1704 finder.findWithAdjustment( initExpr->get_expr() );
1705 for ( Alternative & alt : finder.get_alternatives() ) {
1706 TypeEnvironment newEnv( alt.env );
[e4d829b]1707 AssertionSet needAssertions, haveAssertions;
[62423350]1708 OpenVarSet openVars; // find things in env that don't have a "representative type" and claim those are open vars?
[13deae88]1709 PRINT(
1710 std::cerr << " @ " << toType << " " << initAlt.designation << std::endl;
1711 )
[e4d829b]1712 // It's possible that a cast can throw away some values in a multiply-valued expression. (An example is a
1713 // cast-to-void, which casts from one value to zero.) Figure out the prefix of the subexpression results
1714 // that are cast directly. The candidate is invalid if it has fewer results than there are types to cast
1715 // to.
[62423350]1716 int discardedValues = alt.expr->get_result()->size() - toType->size();
[e4d829b]1717 if ( discardedValues < 0 ) continue;
1718 // xxx - may need to go into tuple types and extract relevant types and use unifyList. Note that currently, this does not
1719 // allow casting a tuple to an atomic type (e.g. (int)([1, 2, 3]))
1720 // unification run for side-effects
[62423350]1721 unify( toType, alt.expr->get_result(), newEnv, needAssertions, haveAssertions, openVars, indexer ); // xxx - do some inspecting on this line... why isn't result bound to initAlt.type??
[e4d829b]1722
[62423350]1723 Cost thisCost = castCost( alt.expr->get_result(), toType, indexer, newEnv );
[e4d829b]1724 if ( thisCost != Cost::infinity ) {
1725 // count one safe conversion for each value that is thrown away
[89be1c68]1726 thisCost.incSafe( discardedValues );
[bb666f64]1727 Alternative newAlt( new InitExpr( restructureCast( alt.expr->clone(), toType ), initAlt.designation->clone() ), newEnv, alt.cost, thisCost );
1728 inferParameters( needAssertions, haveAssertions, newAlt, openVars, back_inserter( candidates ) );
[e4d829b]1729 }
1730 }
1731 }
1732
1733 // findMinCost selects the alternatives with the lowest "cost" members, but has the side effect of copying the
1734 // cvtCost member to the cost member (since the old cost is now irrelevant). Thus, calling findMinCost twice
1735 // selects first based on argument cost, then on conversion cost.
1736 AltList minArgCost;
1737 findMinCost( candidates.begin(), candidates.end(), std::back_inserter( minArgCost ) );
1738 findMinCost( minArgCost.begin(), minArgCost.end(), std::back_inserter( alternatives ) );
1739 }
[c71b256]1740
1741 void AlternativeFinder::Finder::postvisit( InitExpr * ) {
1742 assertf( false, "AlternativeFinder should never see a resolved InitExpr." );
1743 }
1744
1745 void AlternativeFinder::Finder::postvisit( DeletedExpr * ) {
1746 assertf( false, "AlternativeFinder should never see a DeletedExpr." );
1747 }
[51b73452]1748} // namespace ResolvExpr
[a32b204]1749
1750// Local Variables: //
1751// tab-width: 4 //
1752// mode: c++ //
1753// compile-command: "make install" //
1754// End: //
Note: See TracBrowser for help on using the repository browser.