Changes in / [e172f42:a0bd9a2]
- Files:
-
- 31 edited
-
libcfa/prelude/builtins.c (modified) (2 diffs)
-
libcfa/src/common.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/kernel/cluster.hfa (modified) (1 diff)
-
libcfa/src/stdlib.hfa (modified) (1 diff)
-
src/AST/Convert.cpp (modified) (1 diff)
-
src/AST/Expr.cpp (modified) (1 diff)
-
src/AST/Expr.hpp (modified) (2 diffs)
-
src/AST/SymbolTable.cpp (modified) (2 diffs)
-
src/AST/Type.hpp (modified) (1 diff)
-
src/AST/TypeEnvironment.cpp (modified) (1 diff)
-
src/AST/TypeEnvironment.hpp (modified) (1 diff)
-
src/GenPoly/SpecializeNew.cpp (modified) (2 diffs)
-
src/Parser/ExpressionNode.cc (modified) (2 diffs)
-
src/Parser/ExpressionNode.h (modified) (1 diff)
-
src/Parser/parser.yy (modified) (1 diff)
-
src/ResolvExpr/Candidate.hpp (modified) (2 diffs)
-
src/ResolvExpr/CandidateFinder.cpp (modified) (4 diffs)
-
src/ResolvExpr/CandidateFinder.hpp (modified) (1 diff)
-
src/ResolvExpr/CastCost.cc (modified) (1 diff)
-
src/ResolvExpr/CommonType.cc (modified) (4 diffs)
-
src/ResolvExpr/ConversionCost.cc (modified) (5 diffs)
-
src/ResolvExpr/FindOpenVars.cc (modified) (3 diffs)
-
src/ResolvExpr/FindOpenVars.h (modified) (1 diff)
-
src/ResolvExpr/Resolver.cc (modified) (2 diffs)
-
src/ResolvExpr/SatisfyAssertions.cpp (modified) (15 diffs)
-
src/ResolvExpr/Unify.cc (modified) (6 diffs)
-
src/SynTree/Expression.cc (modified) (1 diff)
-
src/SynTree/Expression.h (modified) (1 diff)
-
src/Tuples/TupleAssignment.cc (modified) (1 diff)
-
src/Validate/Autogen.cpp (modified) (5 diffs)
-
tests/collections/vector-demo.cfa (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/prelude/builtins.c
re172f42 ra0bd9a2 149 149 150 150 static inline { 151 int ?\?( int x, unsigned int y ) { __CFA_EXP__(); }151 long int ?\?( int x, unsigned int y ) { __CFA_EXP__(); } 152 152 long int ?\?( long int x, unsigned long int y ) { __CFA_EXP__(); } 153 153 long long int ?\?( long long int x, unsigned long long int y ) { __CFA_EXP__(); } 154 154 // unsigned computation may be faster and larger 155 unsigned int ?\?( unsigned int x, unsigned int y ) { __CFA_EXP__(); }155 unsigned long int ?\?( unsigned int x, unsigned int y ) { __CFA_EXP__(); } 156 156 unsigned long int ?\?( unsigned long int x, unsigned long int y ) { __CFA_EXP__(); } 157 157 unsigned long long int ?\?( unsigned long long int x, unsigned long long int y ) { __CFA_EXP__(); } … … 176 176 177 177 static inline { 178 int ?\=?( int & x, unsigned int y ) { x = x \ y; return x; }178 long int ?\=?( int & x, unsigned int y ) { x = x \ y; return x; } 179 179 long int ?\=?( long int & x, unsigned long int y ) { x = x \ y; return x; } 180 180 long long int ?\=?( long long int & x, unsigned long long int y ) { x = x \ y; return x; } 181 unsigned int ?\=?( unsigned int & x, unsigned int y ) { x = x \ y; return x; }181 unsigned long int ?\=?( unsigned int & x, unsigned int y ) { x = x \ y; return x; } 182 182 unsigned long int ?\=?( unsigned long int & x, unsigned long int y ) { x = x \ y; return x; } 183 183 unsigned long long int ?\=?( unsigned long long int & x, unsigned long long int y ) { x = x \ y; return x; } -
libcfa/src/common.hfa
re172f42 ra0bd9a2 32 32 } // extern "C" 33 33 static inline __attribute__((always_inline)) { 34 unsigned char abs( signed char v ) { return (int)abs( (int)v ); }34 unsigned char abs( signed char v ) { return abs( (int)v ); } 35 35 // use default C routine for int 36 36 unsigned long int abs( long int v ) { return labs( v ); } … … 70 70 unsigned int min( unsigned int v1, unsigned int v2 ) { return v1 < v2 ? v1 : v2; } 71 71 long int min( long int v1, long int v2 ) { return v1 < v2 ? v1 : v2; } 72 unsigned long int min( unsigned long int v1, unsigned longint v2 ) { return v1 < v2 ? v1 : v2; }72 unsigned long int min( unsigned long int v1, unsigned int v2 ) { return v1 < v2 ? v1 : v2; } 73 73 long long int min( long long int v1, long long int v2 ) { return v1 < v2 ? v1 : v2; } 74 unsigned long long int min( unsigned long long int v1, unsigned long longint v2 ) { return v1 < v2 ? v1 : v2; }74 unsigned long long int min( unsigned long long int v1, unsigned int v2 ) { return v1 < v2 ? v1 : v2; } 75 75 forall( T | { int ?<?( T, T ); } ) // generic 76 76 T min( T v1, T v2 ) { return v1 < v2 ? v1 : v2; } -
libcfa/src/concurrency/kernel/cluster.hfa
re172f42 ra0bd9a2 40 40 41 41 // convert to log2 scale but using double 42 static inline __readyQ_avg_t __to_readyQ_avg(unsigned long long intsc) { if(unlikely(0 == intsc)) return 0.0; else return log2( (__readyQ_avg_t)intsc); }42 static inline __readyQ_avg_t __to_readyQ_avg(unsigned long long intsc) { if(unlikely(0 == intsc)) return 0.0; else return log2(intsc); } 43 43 44 44 #define warn_large_before warnf( !strict || old_avg < 35.0, "Suspiciously large previous average: %'lf, %'" PRId64 "ms \n", old_avg, program()`ms ) -
libcfa/src/stdlib.hfa
re172f42 ra0bd9a2 367 367 368 368 char random( void ) { return (unsigned long int)random(); } 369 char random( char u ) { return (unsigned long int)random( (unsigned long int)u ); } // [0,u)369 char random( char u ) { return random( (unsigned long int)u ); } // [0,u) 370 370 char random( char l, char u ) { return random( (unsigned long int)l, (unsigned long int)u ); } // [l,u) 371 371 int random( void ) { return (long int)random(); } 372 int random( int u ) { return (long int)random( (long int)u ); } // [0,u]372 int random( int u ) { return random( (long int)u ); } // [0,u] 373 373 int random( int l, int u ) { return random( (long int)l, (long int)u ); } // [l,u) 374 374 unsigned int random( void ) { return (unsigned long int)random(); } 375 unsigned int random( unsigned int u ) { return (unsigned long int)random( (unsigned long int)u ); } // [0,u]375 unsigned int random( unsigned int u ) { return random( (unsigned long int)u ); } // [0,u] 376 376 unsigned int random( unsigned int l, unsigned int u ) { return random( (unsigned long int)l, (unsigned long int)u ); } // [l,u) 377 377 } // distribution -
src/AST/Convert.cpp
re172f42 ra0bd9a2 2343 2343 old->location, 2344 2344 GET_ACCEPT_1(arg, Expr), 2345 old->isGenerated ? ast::GeneratedCast : ast::ExplicitCast, 2346 (ast::CastExpr::CastKind) old->kind 2345 old->isGenerated ? ast::GeneratedCast : ast::ExplicitCast 2347 2346 ) 2348 2347 ); -
src/AST/Expr.cpp
re172f42 ra0bd9a2 186 186 // --- CastExpr 187 187 188 CastExpr::CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g , CastKind kind)189 : Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ) , kind( kind ){}188 CastExpr::CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g ) 189 : Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ) {} 190 190 191 191 bool CastExpr::get_lvalue() const { -
src/AST/Expr.hpp
re172f42 ra0bd9a2 55 55 const Expr * e ) 56 56 : decl( id ), declptr( declptr ), actualType( actual ), formalType( formal ), expr( e ) {} 57 58 operator bool() {return declptr;}59 57 }; 60 58 … … 337 335 GeneratedFlag isGenerated; 338 336 339 enum CastKind {340 Default, // C341 Coerce, // reinterpret cast342 Return // overload selection343 };344 345 CastKind kind = Default;346 347 337 CastExpr( const CodeLocation & loc, const Expr * a, const Type * to, 348 GeneratedFlag g = GeneratedCast , CastKind kind = Default ) : Expr( loc, to ), arg( a ), isGenerated( g ), kind( kind) {}338 GeneratedFlag g = GeneratedCast ) : Expr( loc, to ), arg( a ), isGenerated( g ) {} 349 339 /// Cast-to-void 350 CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g = GeneratedCast , CastKind kind = Default);340 CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g = GeneratedCast ); 351 341 352 342 /// Wrap a cast expression around an existing expression (always generated) -
src/AST/SymbolTable.cpp
re172f42 ra0bd9a2 19 19 20 20 #include "Copy.hpp" 21 #include <iostream>22 #include <algorithm>23 24 21 #include "Decl.hpp" 25 22 #include "Expr.hpp" … … 206 203 out.push_back(decl.second); 207 204 } 208 209 // std::cerr << otypeKey << ' ' << out.size() << std::endl;210 205 } 211 206 -
src/AST/Type.hpp
re172f42 ra0bd9a2 451 451 bool operator==(const TypeEnvKey & other) const; 452 452 bool operator<(const TypeEnvKey & other) const; 453 operator bool() {return base;} 454 }; 455 453 }; 456 454 457 455 /// tuple type e.g. `[int, char]` -
src/AST/TypeEnvironment.cpp
re172f42 ra0bd9a2 135 135 } 136 136 } 137 //sub.normalize();137 sub.normalize(); 138 138 } 139 139 -
src/AST/TypeEnvironment.hpp
re172f42 ra0bd9a2 63 63 64 64 int cmp = d1->var->name.compare( d2->var->name ); 65 return cmp >0 || ( cmp == 0 && d1->result < d2->result );65 return cmp < 0 || ( cmp == 0 && d1->result < d2->result ); 66 66 } 67 67 }; -
src/GenPoly/SpecializeNew.cpp
re172f42 ra0bd9a2 113 113 using namespace ResolvExpr; 114 114 ast::OpenVarSet openVars, closedVars; 115 ast::AssertionSet need, have; // unused 116 ast::TypeEnvironment env; // unused 117 // findOpenVars( formalType, openVars, closedVars, need, have, FirstClosed ); 118 findOpenVars( actualType, openVars, closedVars, need, have, env, FirstOpen ); 115 ast::AssertionSet need, have; 116 findOpenVars( formalType, openVars, closedVars, need, have, FirstClosed ); 117 findOpenVars( actualType, openVars, closedVars, need, have, FirstOpen ); 119 118 for ( const ast::OpenVarSet::value_type & openVar : openVars ) { 120 119 const ast::Type * boundType = subs->lookup( openVar.first ); … … 126 125 if ( closedVars.find( *inst ) == closedVars.end() ) { 127 126 return true; 128 }129 else {130 assertf(false, "closed: %s", inst->name.c_str());131 127 } 132 128 // Otherwise, the variable is bound to a concrete type. -
src/Parser/ExpressionNode.cc
re172f42 ra0bd9a2 601 601 ast::Expr * build_cast( const CodeLocation & location, 602 602 DeclarationNode * decl_node, 603 ExpressionNode * expr_node, 604 ast::CastExpr::CastKind kind ) { 603 ExpressionNode * expr_node ) { 605 604 ast::Type * targetType = maybeMoveBuildType( decl_node ); 606 605 if ( dynamic_cast<ast::VoidType *>( targetType ) ) { … … 608 607 return new ast::CastExpr( location, 609 608 maybeMoveBuild( expr_node ), 610 ast::ExplicitCast , kind);609 ast::ExplicitCast ); 611 610 } else { 612 611 return new ast::CastExpr( location, 613 612 maybeMoveBuild( expr_node ), 614 613 targetType, 615 ast::ExplicitCast , kind);614 ast::ExplicitCast ); 616 615 } // if 617 616 } // build_cast -
src/Parser/ExpressionNode.h
re172f42 ra0bd9a2 69 69 ast::DimensionExpr * build_dimensionref( const CodeLocation &, const std::string * name ); 70 70 71 ast::Expr * build_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node , ast::CastExpr::CastKind kind = ast::CastExpr::Default);71 ast::Expr * build_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node ); 72 72 ast::Expr * build_keyword_cast( const CodeLocation &, ast::AggregateDecl::Aggregate target, ExpressionNode * expr_node ); 73 73 ast::Expr * build_virtual_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node ); -
src/Parser/parser.yy
re172f42 ra0bd9a2 931 931 { $$ = new ExpressionNode( new ast::VirtualCastExpr( yylloc, maybeMoveBuild( $5 ), maybeMoveBuildType( $3 ) ) ); } 932 932 | '(' RETURN type_no_function ')' cast_expression // CFA 933 { $$ = new ExpressionNode( build_cast( yylloc, $3, $5, ast::CastExpr::Return ) ); }933 { SemanticError( yylloc, "Return cast is currently unimplemented." ); $$ = nullptr; } 934 934 | '(' COERCE type_no_function ')' cast_expression // CFA 935 935 { SemanticError( yylloc, "Coerce cast is currently unimplemented." ); $$ = nullptr; } -
src/ResolvExpr/Candidate.hpp
re172f42 ra0bd9a2 91 91 92 92 /// Holdover behaviour from old `findMinCost` -- xxx -- can maybe be eliminated? 93 /*94 93 static inline void promoteCvtCost( CandidateList & candidates ) { 95 94 for ( CandidateRef & r : candidates ) { … … 97 96 } 98 97 } 99 */100 98 101 99 void print( std::ostream & os, const Candidate & cand, Indenter indent = {} ); -
src/ResolvExpr/CandidateFinder.cpp
re172f42 ra0bd9a2 25 25 #include "AdjustExprType.hpp" 26 26 #include "Candidate.hpp" 27 #include "CastCost.hpp" // for castCost 27 28 #include "CompilationState.h" 29 #include "ConversionCost.h" // for conversionCast 28 30 #include "Cost.h" 29 #include " CastCost.hpp"31 #include "ExplodedArg.hpp" 30 32 #include "PolyCost.hpp" 31 #include "SpecCost.hpp"32 #include "ConversionCost.h"33 #include "ExplodedArg.hpp"34 33 #include "RenameVars.h" // for renameTyVars 35 34 #include "Resolver.h" 36 35 #include "ResolveTypeof.h" 37 #include "WidenMode.h"38 36 #include "SatisfyAssertions.hpp" 39 #include "typeops.h" // for adjustExprType, conversionCost, polyCost, specCost 37 #include "SpecCost.hpp" 38 #include "typeops.h" // for combos 40 39 #include "Unify.h" 41 40 #include "AST/Expr.hpp" … … 56 55 namespace ResolvExpr { 57 56 57 /// Unique identifier for matching expression resolutions to their requesting expression 58 UniqueId globalResnSlot = 0; 59 60 namespace { 61 /// First index is which argument, second is which alternative, third is which exploded element 62 using ExplodedArgs_new = std::deque< std::vector< ExplodedArg > >; 63 64 /// Returns a list of alternatives with the minimum cost in the given list 65 CandidateList findMinCost( const CandidateList & candidates ) { 66 CandidateList out; 67 Cost minCost = Cost::infinity; 68 for ( const CandidateRef & r : candidates ) { 69 if ( r->cost < minCost ) { 70 minCost = r->cost; 71 out.clear(); 72 out.emplace_back( r ); 73 } else if ( r->cost == minCost ) { 74 out.emplace_back( r ); 75 } 76 } 77 return out; 78 } 79 80 /// Computes conversion cost for a given expression to a given type 81 const ast::Expr * computeExpressionConversionCost( 82 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 83 ) { 84 Cost convCost = computeConversionCost( 85 arg->result, paramType, arg->get_lvalue(), symtab, env ); 86 outCost += convCost; 87 88 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 89 // conversion. Ignore poly cost for now, since this requires resolution of the cast to 90 // infer parameters and this does not currently work for the reason stated below 91 Cost tmpCost = convCost; 92 tmpCost.incPoly( -tmpCost.get_polyCost() ); 93 if ( tmpCost != Cost::zero ) { 94 ast::ptr< ast::Type > newType = paramType; 95 env.apply( newType ); 96 return new ast::CastExpr{ arg, newType }; 97 98 // xxx - *should* be able to resolve this cast, but at the moment pointers are not 99 // castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 100 // once this is fixed it should be possible to resolve the cast. 101 // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 102 // but it shouldn't be because this makes the conversion from DT* to DT* since 103 // commontype(zero_t, DT*) is DT*, rather than nothing 104 105 // CandidateFinder finder{ symtab, env }; 106 // finder.find( arg, ResolvMode::withAdjustment() ); 107 // assertf( finder.candidates.size() > 0, 108 // "Somehow castable expression failed to find alternatives." ); 109 // assertf( finder.candidates.size() == 1, 110 // "Somehow got multiple alternatives for known cast expression." ); 111 // return finder.candidates.front()->expr; 112 } 113 114 return arg; 115 } 116 117 /// Computes conversion cost for a given candidate 118 Cost computeApplicationConversionCost( 119 CandidateRef cand, const ast::SymbolTable & symtab 120 ) { 121 auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >(); 122 auto pointer = appExpr->func->result.strict_as< ast::PointerType >(); 123 auto function = pointer->base.strict_as< ast::FunctionType >(); 124 125 Cost convCost = Cost::zero; 126 const auto & params = function->params; 127 auto param = params.begin(); 128 auto & args = appExpr->args; 129 130 for ( unsigned i = 0; i < args.size(); ++i ) { 131 const ast::Type * argType = args[i]->result; 132 PRINT( 133 std::cerr << "arg expression:" << std::endl; 134 ast::print( std::cerr, args[i], 2 ); 135 std::cerr << "--- results are" << std::endl; 136 ast::print( std::cerr, argType, 2 ); 137 ) 138 139 if ( param == params.end() ) { 140 if ( function->isVarArgs ) { 141 convCost.incUnsafe(); 142 PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 143 << convCost << std::endl; ; ) 144 // convert reference-typed expressions into value-typed expressions 145 cand->expr = ast::mutate_field_index( 146 appExpr, &ast::ApplicationExpr::args, i, 147 referenceToRvalueConversion( args[i], convCost ) ); 148 continue; 149 } else return Cost::infinity; 150 } 151 152 if ( auto def = args[i].as< ast::DefaultArgExpr >() ) { 153 // Default arguments should be free - don't include conversion cost. 154 // Unwrap them here because they are not relevant to the rest of the system 155 cand->expr = ast::mutate_field_index( 156 appExpr, &ast::ApplicationExpr::args, i, def->expr ); 157 ++param; 158 continue; 159 } 160 161 // mark conversion cost and also specialization cost of param type 162 // const ast::Type * paramType = (*param)->get_type(); 163 cand->expr = ast::mutate_field_index( 164 appExpr, &ast::ApplicationExpr::args, i, 165 computeExpressionConversionCost( 166 args[i], *param, symtab, cand->env, convCost ) ); 167 convCost.decSpec( specCost( *param ) ); 168 ++param; // can't be in for-loop update because of the continue 169 } 170 171 if ( param != params.end() ) return Cost::infinity; 172 173 // specialization cost of return types can't be accounted for directly, it disables 174 // otherwise-identical calls, like this example based on auto-newline in the I/O lib: 175 // 176 // forall(otype OS) { 177 // void ?|?(OS&, int); // with newline 178 // OS& ?|?(OS&, int); // no newline, always chosen due to more specialization 179 // } 180 181 // mark type variable and specialization cost of forall clause 182 convCost.incVar( function->forall.size() ); 183 convCost.decSpec( function->assertions.size() ); 184 185 return convCost; 186 } 187 188 void makeUnifiableVars( 189 const ast::FunctionType * type, ast::OpenVarSet & unifiableVars, 190 ast::AssertionSet & need 191 ) { 192 for ( auto & tyvar : type->forall ) { 193 unifiableVars[ *tyvar ] = ast::TypeData{ tyvar->base }; 194 } 195 for ( auto & assn : type->assertions ) { 196 need[ assn ].isUsed = true; 197 } 198 } 199 200 /// Gets a default value from an initializer, nullptr if not present 201 const ast::ConstantExpr * getDefaultValue( const ast::Init * init ) { 202 if ( auto si = dynamic_cast< const ast::SingleInit * >( init ) ) { 203 if ( auto ce = si->value.as< ast::CastExpr >() ) { 204 return ce->arg.as< ast::ConstantExpr >(); 205 } else { 206 return si->value.as< ast::ConstantExpr >(); 207 } 208 } 209 return nullptr; 210 } 211 212 /// State to iteratively build a match of parameter expressions to arguments 213 struct ArgPack { 214 std::size_t parent; ///< Index of parent pack 215 ast::ptr< ast::Expr > expr; ///< The argument stored here 216 Cost cost; ///< The cost of this argument 217 ast::TypeEnvironment env; ///< Environment for this pack 218 ast::AssertionSet need; ///< Assertions outstanding for this pack 219 ast::AssertionSet have; ///< Assertions found for this pack 220 ast::OpenVarSet open; ///< Open variables for this pack 221 unsigned nextArg; ///< Index of next argument in arguments list 222 unsigned tupleStart; ///< Number of tuples that start at this index 223 unsigned nextExpl; ///< Index of next exploded element 224 unsigned explAlt; ///< Index of alternative for nextExpl > 0 225 226 ArgPack() 227 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 228 tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 229 230 ArgPack( 231 const ast::TypeEnvironment & env, const ast::AssertionSet & need, 232 const ast::AssertionSet & have, const ast::OpenVarSet & open ) 233 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 234 open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 235 236 ArgPack( 237 std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env, 238 ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open, 239 unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero, 240 unsigned nextExpl = 0, unsigned explAlt = 0 ) 241 : parent(parent), expr( expr ), cost( cost ), env( std::move( env ) ), need( std::move( need ) ), 242 have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ), 243 nextExpl( nextExpl ), explAlt( explAlt ) {} 244 245 ArgPack( 246 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 247 ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added ) 248 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( std::move( env ) ), 249 need( std::move( need ) ), have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), 250 tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {} 251 252 /// true if this pack is in the middle of an exploded argument 253 bool hasExpl() const { return nextExpl > 0; } 254 255 /// Gets the list of exploded candidates for this pack 256 const ExplodedArg & getExpl( const ExplodedArgs_new & args ) const { 257 return args[ nextArg-1 ][ explAlt ]; 258 } 259 260 /// Ends a tuple expression, consolidating the appropriate args 261 void endTuple( const std::vector< ArgPack > & packs ) { 262 // add all expressions in tuple to list, summing cost 263 std::deque< const ast::Expr * > exprs; 264 const ArgPack * pack = this; 265 if ( expr ) { exprs.emplace_front( expr ); } 266 while ( pack->tupleStart == 0 ) { 267 pack = &packs[pack->parent]; 268 exprs.emplace_front( pack->expr ); 269 cost += pack->cost; 270 } 271 // reset pack to appropriate tuple 272 std::vector< ast::ptr< ast::Expr > > exprv( exprs.begin(), exprs.end() ); 273 expr = new ast::TupleExpr{ expr->location, std::move( exprv ) }; 274 tupleStart = pack->tupleStart - 1; 275 parent = pack->parent; 276 } 277 }; 278 279 /// Instantiates an argument to match a parameter, returns false if no matching results left 280 bool instantiateArgument( 281 const CodeLocation & location, 282 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 283 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 284 unsigned nTuples = 0 285 ) { 286 if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) { 287 // paramType is a TupleType -- group args into a TupleExpr 288 ++nTuples; 289 for ( const ast::Type * type : *tupleType ) { 290 // xxx - dropping initializer changes behaviour from previous, but seems correct 291 // ^^^ need to handle the case where a tuple has a default argument 292 if ( ! instantiateArgument( location, 293 type, nullptr, args, results, genStart, symtab, nTuples ) ) return false; 294 nTuples = 0; 295 } 296 // re-constitute tuples for final generation 297 for ( auto i = genStart; i < results.size(); ++i ) { 298 results[i].endTuple( results ); 299 } 300 return true; 301 } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) { 302 // paramType is a ttype, consumes all remaining arguments 303 304 // completed tuples; will be spliced to end of results to finish 305 std::vector< ArgPack > finalResults{}; 306 307 // iterate until all results completed 308 std::size_t genEnd; 309 ++nTuples; 310 do { 311 genEnd = results.size(); 312 313 // add another argument to results 314 for ( std::size_t i = genStart; i < genEnd; ++i ) { 315 unsigned nextArg = results[i].nextArg; 316 317 // use next element of exploded tuple if present 318 if ( results[i].hasExpl() ) { 319 const ExplodedArg & expl = results[i].getExpl( args ); 320 321 unsigned nextExpl = results[i].nextExpl + 1; 322 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; } 323 324 results.emplace_back( 325 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ), 326 copy( results[i].need ), copy( results[i].have ), 327 copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl, 328 results[i].explAlt ); 329 330 continue; 331 } 332 333 // finish result when out of arguments 334 if ( nextArg >= args.size() ) { 335 ArgPack newResult{ 336 results[i].env, results[i].need, results[i].have, results[i].open }; 337 newResult.nextArg = nextArg; 338 const ast::Type * argType = nullptr; 339 340 if ( nTuples > 0 || ! results[i].expr ) { 341 // first iteration or no expression to clone, 342 // push empty tuple expression 343 newResult.parent = i; 344 newResult.expr = new ast::TupleExpr( location, {} ); 345 argType = newResult.expr->result; 346 } else { 347 // clone result to collect tuple 348 newResult.parent = results[i].parent; 349 newResult.cost = results[i].cost; 350 newResult.tupleStart = results[i].tupleStart; 351 newResult.expr = results[i].expr; 352 argType = newResult.expr->result; 353 354 if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) { 355 // the case where a ttype value is passed directly is special, 356 // e.g. for argument forwarding purposes 357 // xxx - what if passing multiple arguments, last of which is 358 // ttype? 359 // xxx - what would happen if unify was changed so that unifying 360 // tuple 361 // types flattened both before unifying lists? then pass in 362 // TupleType (ttype) below. 363 --newResult.tupleStart; 364 } else { 365 // collapse leftover arguments into tuple 366 newResult.endTuple( results ); 367 argType = newResult.expr->result; 368 } 369 } 370 371 // check unification for ttype before adding to final 372 if ( 373 unify( 374 ttype, argType, newResult.env, newResult.need, newResult.have, 375 newResult.open ) 376 ) { 377 finalResults.emplace_back( std::move( newResult ) ); 378 } 379 380 continue; 381 } 382 383 // add each possible next argument 384 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) { 385 const ExplodedArg & expl = args[nextArg][j]; 386 387 // fresh copies of parent parameters for this iteration 388 ast::TypeEnvironment env = results[i].env; 389 ast::OpenVarSet open = results[i].open; 390 391 env.addActual( expl.env, open ); 392 393 // skip empty tuple arguments by (nearly) cloning parent into next gen 394 if ( expl.exprs.empty() ) { 395 results.emplace_back( 396 results[i], std::move( env ), copy( results[i].need ), 397 copy( results[i].have ), std::move( open ), nextArg + 1, expl.cost ); 398 399 continue; 400 } 401 402 // add new result 403 results.emplace_back( 404 i, expl.exprs.front(), std::move( env ), copy( results[i].need ), 405 copy( results[i].have ), std::move( open ), nextArg + 1, nTuples, 406 expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 407 } 408 } 409 410 // reset for next round 411 genStart = genEnd; 412 nTuples = 0; 413 } while ( genEnd != results.size() ); 414 415 // splice final results onto results 416 for ( std::size_t i = 0; i < finalResults.size(); ++i ) { 417 results.emplace_back( std::move( finalResults[i] ) ); 418 } 419 return ! finalResults.empty(); 420 } 421 422 // iterate each current subresult 423 std::size_t genEnd = results.size(); 424 for ( std::size_t i = genStart; i < genEnd; ++i ) { 425 unsigned nextArg = results[i].nextArg; 426 427 // use remainder of exploded tuple if present 428 if ( results[i].hasExpl() ) { 429 const ExplodedArg & expl = results[i].getExpl( args ); 430 const ast::Expr * expr = expl.exprs[ results[i].nextExpl ]; 431 432 ast::TypeEnvironment env = results[i].env; 433 ast::AssertionSet need = results[i].need, have = results[i].have; 434 ast::OpenVarSet open = results[i].open; 435 436 const ast::Type * argType = expr->result; 437 438 PRINT( 439 std::cerr << "param type is "; 440 ast::print( std::cerr, paramType ); 441 std::cerr << std::endl << "arg type is "; 442 ast::print( std::cerr, argType ); 443 std::cerr << std::endl; 444 ) 445 446 if ( unify( paramType, argType, env, need, have, open ) ) { 447 unsigned nextExpl = results[i].nextExpl + 1; 448 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; } 449 450 results.emplace_back( 451 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), nextArg, 452 nTuples, Cost::zero, nextExpl, results[i].explAlt ); 453 } 454 455 continue; 456 } 457 458 // use default initializers if out of arguments 459 if ( nextArg >= args.size() ) { 460 if ( const ast::ConstantExpr * cnst = getDefaultValue( init ) ) { 461 ast::TypeEnvironment env = results[i].env; 462 ast::AssertionSet need = results[i].need, have = results[i].have; 463 ast::OpenVarSet open = results[i].open; 464 465 if ( unify( paramType, cnst->result, env, need, have, open ) ) { 466 results.emplace_back( 467 i, new ast::DefaultArgExpr{ cnst->location, cnst }, std::move( env ), 468 std::move( need ), std::move( have ), std::move( open ), nextArg, nTuples ); 469 } 470 } 471 472 continue; 473 } 474 475 // Check each possible next argument 476 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) { 477 const ExplodedArg & expl = args[nextArg][j]; 478 479 // fresh copies of parent parameters for this iteration 480 ast::TypeEnvironment env = results[i].env; 481 ast::AssertionSet need = results[i].need, have = results[i].have; 482 ast::OpenVarSet open = results[i].open; 483 484 env.addActual( expl.env, open ); 485 486 // skip empty tuple arguments by (nearly) cloning parent into next gen 487 if ( expl.exprs.empty() ) { 488 results.emplace_back( 489 results[i], std::move( env ), std::move( need ), std::move( have ), std::move( open ), 490 nextArg + 1, expl.cost ); 491 492 continue; 493 } 494 495 // consider only first exploded arg 496 const ast::Expr * expr = expl.exprs.front(); 497 const ast::Type * argType = expr->result; 498 499 PRINT( 500 std::cerr << "param type is "; 501 ast::print( std::cerr, paramType ); 502 std::cerr << std::endl << "arg type is "; 503 ast::print( std::cerr, argType ); 504 std::cerr << std::endl; 505 ) 506 507 // attempt to unify types 508 if ( unify( paramType, argType, env, need, have, open ) ) { 509 // add new result 510 results.emplace_back( 511 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), 512 nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 513 } 514 } 515 } 516 517 // reset for next parameter 518 genStart = genEnd; 519 520 return genEnd != results.size(); // were any new results added? 521 } 522 523 /// Generate a cast expression from `arg` to `toType` 524 const ast::Expr * restructureCast( 525 ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast 526 ) { 527 if ( 528 arg->result->size() > 1 529 && ! toType->isVoid() 530 && ! dynamic_cast< const ast::ReferenceType * >( toType ) 531 ) { 532 // Argument is a tuple and the target type is neither void nor a reference. Cast each 533 // member of the tuple to its corresponding target type, producing the tuple of those 534 // cast expressions. If there are more components of the tuple than components in the 535 // target type, then excess components do not come out in the result expression (but 536 // UniqueExpr ensures that the side effects will still be produced) 537 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) { 538 // expressions which may contain side effects require a single unique instance of 539 // the expression 540 arg = new ast::UniqueExpr{ arg->location, arg }; 541 } 542 std::vector< ast::ptr< ast::Expr > > components; 543 for ( unsigned i = 0; i < toType->size(); ++i ) { 544 // cast each component 545 ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i }; 546 components.emplace_back( 547 restructureCast( idx, toType->getComponent( i ), isGenerated ) ); 548 } 549 return new ast::TupleExpr{ arg->location, std::move( components ) }; 550 } else { 551 // handle normally 552 return new ast::CastExpr{ arg->location, arg, toType, isGenerated }; 553 } 554 } 555 556 /// Gets the name from an untyped member expression (must be NameExpr) 557 const std::string & getMemberName( const ast::UntypedMemberExpr * memberExpr ) { 558 if ( memberExpr->member.as< ast::ConstantExpr >() ) { 559 SemanticError( memberExpr, "Indexed access to struct fields unsupported: " ); 560 } 561 562 return memberExpr->member.strict_as< ast::NameExpr >()->name; 563 } 564 565 /// Actually visits expressions to find their candidate interpretations 566 class Finder final : public ast::WithShortCircuiting { 567 const ResolveContext & context; 568 const ast::SymbolTable & symtab; 569 public: 570 // static size_t traceId; 571 CandidateFinder & selfFinder; 572 CandidateList & candidates; 573 const ast::TypeEnvironment & tenv; 574 ast::ptr< ast::Type > & targetType; 575 576 enum Errors { 577 NotFound, 578 NoMatch, 579 ArgsToFew, 580 ArgsToMany, 581 RetsToFew, 582 RetsToMany, 583 NoReason 584 }; 585 586 struct { 587 Errors code = NotFound; 588 } reason; 589 590 Finder( CandidateFinder & f ) 591 : context( f.context ), symtab( context.symtab ), selfFinder( f ), 592 candidates( f.candidates ), tenv( f.env ), targetType( f.targetType ) {} 593 594 void previsit( const ast::Node * ) { visit_children = false; } 595 596 /// Convenience to add candidate to list 597 template<typename... Args> 598 void addCandidate( Args &&... args ) { 599 candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } ); 600 reason.code = NoReason; 601 } 602 603 void postvisit( const ast::ApplicationExpr * applicationExpr ) { 604 addCandidate( applicationExpr, tenv ); 605 } 606 607 /// Set up candidate assertions for inference 608 void inferParameters( CandidateRef & newCand, CandidateList & out ); 609 610 /// Completes a function candidate with arguments located 611 void validateFunctionCandidate( 612 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 613 CandidateList & out ); 614 615 /// Builds a list of candidates for a function, storing them in out 616 void makeFunctionCandidates( 617 const CodeLocation & location, 618 const CandidateRef & func, const ast::FunctionType * funcType, 619 const ExplodedArgs_new & args, CandidateList & out ); 620 621 /// Adds implicit struct-conversions to the alternative list 622 void addAnonConversions( const CandidateRef & cand ); 623 624 /// Adds aggregate member interpretations 625 void addAggMembers( 626 const ast::BaseInstType * aggrInst, const ast::Expr * expr, 627 const Candidate & cand, const Cost & addedCost, const std::string & name 628 ); 629 630 /// Adds tuple member interpretations 631 void addTupleMembers( 632 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 633 const Cost & addedCost, const ast::Expr * member 634 ); 635 636 /// true if expression is an lvalue 637 static bool isLvalue( const ast::Expr * x ) { 638 return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() ); 639 } 640 641 void postvisit( const ast::UntypedExpr * untypedExpr ); 642 void postvisit( const ast::VariableExpr * variableExpr ); 643 void postvisit( const ast::ConstantExpr * constantExpr ); 644 void postvisit( const ast::SizeofExpr * sizeofExpr ); 645 void postvisit( const ast::AlignofExpr * alignofExpr ); 646 void postvisit( const ast::AddressExpr * addressExpr ); 647 void postvisit( const ast::LabelAddressExpr * labelExpr ); 648 void postvisit( const ast::CastExpr * castExpr ); 649 void postvisit( const ast::VirtualCastExpr * castExpr ); 650 void postvisit( const ast::KeywordCastExpr * castExpr ); 651 void postvisit( const ast::UntypedMemberExpr * memberExpr ); 652 void postvisit( const ast::MemberExpr * memberExpr ); 653 void postvisit( const ast::NameExpr * nameExpr ); 654 void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ); 655 void postvisit( const ast::OffsetofExpr * offsetofExpr ); 656 void postvisit( const ast::OffsetPackExpr * offsetPackExpr ); 657 void postvisit( const ast::LogicalExpr * logicalExpr ); 658 void postvisit( const ast::ConditionalExpr * conditionalExpr ); 659 void postvisit( const ast::CommaExpr * commaExpr ); 660 void postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ); 661 void postvisit( const ast::ConstructorExpr * ctorExpr ); 662 void postvisit( const ast::RangeExpr * rangeExpr ); 663 void postvisit( const ast::UntypedTupleExpr * tupleExpr ); 664 void postvisit( const ast::TupleExpr * tupleExpr ); 665 void postvisit( const ast::TupleIndexExpr * tupleExpr ); 666 void postvisit( const ast::TupleAssignExpr * tupleExpr ); 667 void postvisit( const ast::UniqueExpr * unqExpr ); 668 void postvisit( const ast::StmtExpr * stmtExpr ); 669 void postvisit( const ast::UntypedInitExpr * initExpr ); 670 671 void postvisit( const ast::InitExpr * ) { 672 assertf( false, "CandidateFinder should never see a resolved InitExpr." ); 673 } 674 675 void postvisit( const ast::DeletedExpr * ) { 676 assertf( false, "CandidateFinder should never see a DeletedExpr." ); 677 } 678 679 void postvisit( const ast::GenericExpr * ) { 680 assertf( false, "_Generic is not yet supported." ); 681 } 682 }; 683 684 /// Set up candidate assertions for inference 685 void Finder::inferParameters( CandidateRef & newCand, CandidateList & out ) { 686 // Set need bindings for any unbound assertions 687 UniqueId crntResnSlot = 0; // matching ID for this expression's assertions 688 for ( auto & assn : newCand->need ) { 689 // skip already-matched assertions 690 if ( assn.second.resnSlot != 0 ) continue; 691 // assign slot for expression if needed 692 if ( crntResnSlot == 0 ) { crntResnSlot = ++globalResnSlot; } 693 // fix slot to assertion 694 assn.second.resnSlot = crntResnSlot; 695 } 696 // pair slot to expression 697 if ( crntResnSlot != 0 ) { 698 newCand->expr.get_and_mutate()->inferred.resnSlots().emplace_back( crntResnSlot ); 699 } 700 701 // add to output list; assertion satisfaction will occur later 702 out.emplace_back( newCand ); 703 } 704 705 /// Completes a function candidate with arguments located 706 void Finder::validateFunctionCandidate( 707 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 708 CandidateList & out 709 ) { 710 ast::ApplicationExpr * appExpr = 711 new ast::ApplicationExpr{ func->expr->location, func->expr }; 712 // sum cost and accumulate arguments 713 std::deque< const ast::Expr * > args; 714 Cost cost = func->cost; 715 const ArgPack * pack = &result; 716 while ( pack->expr ) { 717 args.emplace_front( pack->expr ); 718 cost += pack->cost; 719 pack = &results[pack->parent]; 720 } 721 std::vector< ast::ptr< ast::Expr > > vargs( args.begin(), args.end() ); 722 appExpr->args = std::move( vargs ); 723 // build and validate new candidate 724 auto newCand = 725 std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost ); 726 PRINT( 727 std::cerr << "instantiate function success: " << appExpr << std::endl; 728 std::cerr << "need assertions:" << std::endl; 729 ast::print( std::cerr, result.need, 2 ); 730 ) 731 inferParameters( newCand, out ); 732 } 733 734 /// Builds a list of candidates for a function, storing them in out 735 void Finder::makeFunctionCandidates( 736 const CodeLocation & location, 737 const CandidateRef & func, const ast::FunctionType * funcType, 738 const ExplodedArgs_new & args, CandidateList & out 739 ) { 740 ast::OpenVarSet funcOpen; 741 ast::AssertionSet funcNeed, funcHave; 742 ast::TypeEnvironment funcEnv{ func->env }; 743 makeUnifiableVars( funcType, funcOpen, funcNeed ); 744 // add all type variables as open variables now so that those not used in the 745 // parameter list are still considered open 746 funcEnv.add( funcType->forall ); 747 748 if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) { 749 // attempt to narrow based on expected target type 750 const ast::Type * returnType = funcType->returns.front(); 751 if ( ! unify( 752 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen ) 753 ) { 754 // unification failed, do not pursue this candidate 755 return; 756 } 757 } 758 759 // iteratively build matches, one parameter at a time 760 std::vector< ArgPack > results; 761 results.emplace_back( funcEnv, funcNeed, funcHave, funcOpen ); 762 std::size_t genStart = 0; 763 764 // xxx - how to handle default arg after change to ftype representation? 765 if (const ast::VariableExpr * varExpr = func->expr.as<ast::VariableExpr>()) { 766 if (const ast::FunctionDecl * funcDecl = varExpr->var.as<ast::FunctionDecl>()) { 767 // function may have default args only if directly calling by name 768 // must use types on candidate however, due to RenameVars substitution 769 auto nParams = funcType->params.size(); 770 771 for (size_t i=0; i<nParams; ++i) { 772 auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>(); 773 if (!instantiateArgument( location, 774 funcType->params[i], obj->init, args, results, genStart, symtab)) return; 775 } 776 goto endMatch; 777 } 778 } 779 for ( const auto & param : funcType->params ) { 780 // Try adding the arguments corresponding to the current parameter to the existing 781 // matches 782 // no default args for indirect calls 783 if ( ! instantiateArgument( location, 784 param, nullptr, args, results, genStart, symtab ) ) return; 785 } 786 787 endMatch: 788 if ( funcType->isVarArgs ) { 789 // append any unused arguments to vararg pack 790 std::size_t genEnd; 791 do { 792 genEnd = results.size(); 793 794 // iterate results 795 for ( std::size_t i = genStart; i < genEnd; ++i ) { 796 unsigned nextArg = results[i].nextArg; 797 798 // use remainder of exploded tuple if present 799 if ( results[i].hasExpl() ) { 800 const ExplodedArg & expl = results[i].getExpl( args ); 801 802 unsigned nextExpl = results[i].nextExpl + 1; 803 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; } 804 805 results.emplace_back( 806 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ), 807 copy( results[i].need ), copy( results[i].have ), 808 copy( results[i].open ), nextArg, 0, Cost::zero, nextExpl, 809 results[i].explAlt ); 810 811 continue; 812 } 813 814 // finish result when out of arguments 815 if ( nextArg >= args.size() ) { 816 validateFunctionCandidate( func, results[i], results, out ); 817 818 continue; 819 } 820 821 // add each possible next argument 822 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) { 823 const ExplodedArg & expl = args[nextArg][j]; 824 825 // fresh copies of parent parameters for this iteration 826 ast::TypeEnvironment env = results[i].env; 827 ast::OpenVarSet open = results[i].open; 828 829 env.addActual( expl.env, open ); 830 831 // skip empty tuple arguments by (nearly) cloning parent into next gen 832 if ( expl.exprs.empty() ) { 833 results.emplace_back( 834 results[i], std::move( env ), copy( results[i].need ), 835 copy( results[i].have ), std::move( open ), nextArg + 1, 836 expl.cost ); 837 838 continue; 839 } 840 841 // add new result 842 results.emplace_back( 843 i, expl.exprs.front(), std::move( env ), copy( results[i].need ), 844 copy( results[i].have ), std::move( open ), nextArg + 1, 0, expl.cost, 845 expl.exprs.size() == 1 ? 0 : 1, j ); 846 } 847 } 848 849 genStart = genEnd; 850 } while( genEnd != results.size() ); 851 } else { 852 // filter out the results that don't use all the arguments 853 for ( std::size_t i = genStart; i < results.size(); ++i ) { 854 ArgPack & result = results[i]; 855 if ( ! result.hasExpl() && result.nextArg >= args.size() ) { 856 validateFunctionCandidate( func, result, results, out ); 857 } 858 } 859 } 860 } 861 862 /// Adds implicit struct-conversions to the alternative list 863 void Finder::addAnonConversions( const CandidateRef & cand ) { 864 // adds anonymous member interpretations whenever an aggregate value type is seen. 865 // it's okay for the aggregate expression to have reference type -- cast it to the 866 // base type to treat the aggregate as the referenced value 867 ast::ptr< ast::Expr > aggrExpr( cand->expr ); 868 ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result; 869 cand->env.apply( aggrType ); 870 871 if ( aggrType.as< ast::ReferenceType >() ) { 872 aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() }; 873 } 874 875 if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) { 876 addAggMembers( structInst, aggrExpr, *cand, Cost::safe, "" ); 877 } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) { 878 addAggMembers( unionInst, aggrExpr, *cand, Cost::safe, "" ); 879 } 880 } 881 882 /// Adds aggregate member interpretations 883 void Finder::addAggMembers( 884 const ast::BaseInstType * aggrInst, const ast::Expr * expr, 885 const Candidate & cand, const Cost & addedCost, const std::string & name 886 ) { 887 for ( const ast::Decl * decl : aggrInst->lookup( name ) ) { 888 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl ); 889 CandidateRef newCand = std::make_shared<Candidate>( 890 cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost ); 891 // add anonymous member interpretations whenever an aggregate value type is seen 892 // as a member expression 893 addAnonConversions( newCand ); 894 candidates.emplace_back( std::move( newCand ) ); 895 } 896 } 897 898 /// Adds tuple member interpretations 899 void Finder::addTupleMembers( 900 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 901 const Cost & addedCost, const ast::Expr * member 902 ) { 903 if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) { 904 // get the value of the constant expression as an int, must be between 0 and the 905 // length of the tuple to have meaning 906 long long val = constantExpr->intValue(); 907 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) { 908 addCandidate( 909 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 910 addedCost ); 911 } 912 } 913 } 914 915 void Finder::postvisit( const ast::UntypedExpr * untypedExpr ) { 916 std::vector< CandidateFinder > argCandidates = 917 selfFinder.findSubExprs( untypedExpr->args ); 918 919 // take care of possible tuple assignments 920 // if not tuple assignment, handled as normal function call 921 Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates ); 922 923 CandidateFinder funcFinder( context, tenv ); 924 if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) { 925 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name); 926 if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) { 927 assertf(!argCandidates.empty(), "special function call without argument"); 928 for (auto & firstArgCand: argCandidates[0]) { 929 ast::ptr<ast::Type> argType = firstArgCand->expr->result; 930 firstArgCand->env.apply(argType); 931 // strip references 932 // xxx - is this correct? 933 while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base; 934 935 // convert 1-tuple to plain type 936 if (auto tuple = argType.as<ast::TupleType>()) { 937 if (tuple->size() == 1) { 938 argType = tuple->types[0]; 939 } 940 } 941 942 // if argType is an unbound type parameter, all special functions need to be searched. 943 if (isUnboundType(argType)) { 944 funcFinder.otypeKeys.clear(); 945 break; 946 } 947 948 if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer); 949 // else if (const ast::EnumInstType * enumInst = argType.as<ast::EnumInstType>()) { 950 // const ast::EnumDecl * enumDecl = enumInst->base; // Here 951 // if ( const ast::Type* enumType = enumDecl->base ) { 952 // // instance of enum (T) is a instance of type (T) 953 // funcFinder.otypeKeys.insert(Mangle::mangle(enumType, Mangle::NoGenericParams | Mangle::Type)); 954 // } else { 955 // // instance of an untyped enum is techically int 956 // funcFinder.otypeKeys.insert(Mangle::mangle(enumDecl, Mangle::NoGenericParams | Mangle::Type)); 957 // } 958 // } 959 else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type)); 960 } 961 } 962 } 963 // if candidates are already produced, do not fail 964 // xxx - is it possible that handleTupleAssignment and main finder both produce candidates? 965 // this means there exists ctor/assign functions with a tuple as first parameter. 966 ResolvMode mode = { 967 true, // adjust 968 !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name 969 selfFinder.candidates.empty() // failfast if other options are not found 970 }; 971 funcFinder.find( untypedExpr->func, mode ); 972 // short-circuit if no candidates 973 // if ( funcFinder.candidates.empty() ) return; 974 975 reason.code = NoMatch; 976 977 // find function operators 978 ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" }; // ??? why not ?{} 979 CandidateFinder opFinder( context, tenv ); 980 // okay if there aren't any function operations 981 opFinder.find( opExpr, ResolvMode::withoutFailFast() ); 982 PRINT( 983 std::cerr << "known function ops:" << std::endl; 984 print( std::cerr, opFinder.candidates, 1 ); 985 ) 986 987 // pre-explode arguments 988 ExplodedArgs_new argExpansions; 989 for ( const CandidateFinder & args : argCandidates ) { 990 argExpansions.emplace_back(); 991 auto & argE = argExpansions.back(); 992 for ( const CandidateRef & arg : args ) { argE.emplace_back( *arg, symtab ); } 993 } 994 995 // Find function matches 996 CandidateList found; 997 SemanticErrorException errors; 998 for ( CandidateRef & func : funcFinder ) { 999 try { 1000 PRINT( 1001 std::cerr << "working on alternative:" << std::endl; 1002 print( std::cerr, *func, 2 ); 1003 ) 1004 1005 // check if the type is a pointer to function 1006 const ast::Type * funcResult = func->expr->result->stripReferences(); 1007 if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) { 1008 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 1009 CandidateRef newFunc{ new Candidate{ *func } }; 1010 newFunc->expr = 1011 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 1012 makeFunctionCandidates( untypedExpr->location, 1013 newFunc, function, argExpansions, found ); 1014 } 1015 } else if ( 1016 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 1017 ) { 1018 if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) { 1019 if ( auto function = clz->bound.as< ast::FunctionType >() ) { 1020 CandidateRef newFunc{ new Candidate{ *func } }; 1021 newFunc->expr = 1022 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 1023 makeFunctionCandidates( untypedExpr->location, 1024 newFunc, function, argExpansions, found ); 1025 } 1026 } 1027 } 1028 } catch ( SemanticErrorException & e ) { errors.append( e ); } 1029 } 1030 1031 // Find matches on function operators `?()` 1032 if ( ! opFinder.candidates.empty() ) { 1033 // add exploded function alternatives to front of argument list 1034 std::vector< ExplodedArg > funcE; 1035 funcE.reserve( funcFinder.candidates.size() ); 1036 for ( const CandidateRef & func : funcFinder ) { 1037 funcE.emplace_back( *func, symtab ); 1038 } 1039 argExpansions.emplace_front( std::move( funcE ) ); 1040 1041 for ( const CandidateRef & op : opFinder ) { 1042 try { 1043 // check if type is pointer-to-function 1044 const ast::Type * opResult = op->expr->result->stripReferences(); 1045 if ( auto pointer = dynamic_cast< const ast::PointerType * >( opResult ) ) { 1046 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 1047 CandidateRef newOp{ new Candidate{ *op} }; 1048 newOp->expr = 1049 referenceToRvalueConversion( newOp->expr, newOp->cost ); 1050 makeFunctionCandidates( untypedExpr->location, 1051 newOp, function, argExpansions, found ); 1052 } 1053 } 1054 } catch ( SemanticErrorException & e ) { errors.append( e ); } 1055 } 1056 } 1057 1058 // Implement SFINAE; resolution errors are only errors if there aren't any non-error 1059 // candidates 1060 if ( found.empty() && ! errors.isEmpty() ) { throw errors; } 1061 1062 // Compute conversion costs 1063 for ( CandidateRef & withFunc : found ) { 1064 Cost cvtCost = computeApplicationConversionCost( withFunc, symtab ); 1065 1066 PRINT( 1067 auto appExpr = withFunc->expr.strict_as< ast::ApplicationExpr >(); 1068 auto pointer = appExpr->func->result.strict_as< ast::PointerType >(); 1069 auto function = pointer->base.strict_as< ast::FunctionType >(); 1070 1071 std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl; 1072 std::cerr << "parameters are:" << std::endl; 1073 ast::printAll( std::cerr, function->params, 2 ); 1074 std::cerr << "arguments are:" << std::endl; 1075 ast::printAll( std::cerr, appExpr->args, 2 ); 1076 std::cerr << "bindings are:" << std::endl; 1077 ast::print( std::cerr, withFunc->env, 2 ); 1078 std::cerr << "cost is: " << withFunc->cost << std::endl; 1079 std::cerr << "cost of conversion is:" << cvtCost << std::endl; 1080 ) 1081 1082 if ( cvtCost != Cost::infinity ) { 1083 withFunc->cvtCost = cvtCost; 1084 candidates.emplace_back( std::move( withFunc ) ); 1085 } 1086 } 1087 found = std::move( candidates ); 1088 1089 // use a new list so that candidates are not examined by addAnonConversions twice 1090 CandidateList winners = findMinCost( found ); 1091 promoteCvtCost( winners ); 1092 1093 // function may return a struct/union value, in which case we need to add candidates 1094 // for implicit conversions to each of the anonymous members, which must happen after 1095 // `findMinCost`, since anon conversions are never the cheapest 1096 for ( const CandidateRef & c : winners ) { 1097 addAnonConversions( c ); 1098 } 1099 spliceBegin( candidates, winners ); 1100 1101 if ( candidates.empty() && targetType && ! targetType->isVoid() ) { 1102 // If resolution is unsuccessful with a target type, try again without, since it 1103 // will sometimes succeed when it wouldn't with a target type binding. 1104 // For example: 1105 // forall( otype T ) T & ?[]( T *, ptrdiff_t ); 1106 // const char * x = "hello world"; 1107 // unsigned char ch = x[0]; 1108 // Fails with simple return type binding (xxx -- check this!) as follows: 1109 // * T is bound to unsigned char 1110 // * (x: const char *) is unified with unsigned char *, which fails 1111 // xxx -- fix this better 1112 targetType = nullptr; 1113 postvisit( untypedExpr ); 1114 } 1115 } 1116 1117 void Finder::postvisit( const ast::AddressExpr * addressExpr ) { 1118 CandidateFinder finder( context, tenv ); 1119 finder.find( addressExpr->arg ); 1120 1121 if ( finder.candidates.empty() ) return; 1122 1123 reason.code = NoMatch; 1124 1125 for ( CandidateRef & r : finder.candidates ) { 1126 if ( ! isLvalue( r->expr ) ) continue; 1127 addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } ); 1128 } 1129 } 1130 1131 void Finder::postvisit( const ast::LabelAddressExpr * labelExpr ) { 1132 addCandidate( labelExpr, tenv ); 1133 } 1134 1135 void Finder::postvisit( const ast::CastExpr * castExpr ) { 1136 ast::ptr< ast::Type > toType = castExpr->result; 1137 assert( toType ); 1138 toType = resolveTypeof( toType, context ); 1139 toType = adjustExprType( toType, tenv, symtab ); 1140 1141 CandidateFinder finder( context, tenv, toType ); 1142 finder.find( castExpr->arg, ResolvMode::withAdjustment() ); 1143 1144 if ( !finder.candidates.empty() ) reason.code = NoMatch; 1145 1146 CandidateList matches; 1147 for ( CandidateRef & cand : finder.candidates ) { 1148 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have; 1149 ast::OpenVarSet open( cand->open ); 1150 1151 cand->env.extractOpenVars( open ); 1152 1153 // It is possible that a cast can throw away some values in a multiply-valued 1154 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 1155 // subexpression results that are cast directly. The candidate is invalid if it 1156 // has fewer results than there are types to cast to. 1157 int discardedValues = cand->expr->result->size() - toType->size(); 1158 if ( discardedValues < 0 ) continue; 1159 1160 // unification run for side-effects 1161 unify( toType, cand->expr->result, cand->env, need, have, open ); 1162 Cost thisCost = 1163 (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast) 1164 ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env ) 1165 : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env ); 1166 1167 PRINT( 1168 std::cerr << "working on cast with result: " << toType << std::endl; 1169 std::cerr << "and expr type: " << cand->expr->result << std::endl; 1170 std::cerr << "env: " << cand->env << std::endl; 1171 ) 1172 if ( thisCost != Cost::infinity ) { 1173 PRINT( 1174 std::cerr << "has finite cost." << std::endl; 1175 ) 1176 // count one safe conversion for each value that is thrown away 1177 thisCost.incSafe( discardedValues ); 1178 CandidateRef newCand = std::make_shared<Candidate>( 1179 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1180 copy( cand->env ), std::move( open ), std::move( need ), cand->cost, 1181 cand->cost + thisCost ); 1182 inferParameters( newCand, matches ); 1183 } 1184 } 1185 1186 // select first on argument cost, then conversion cost 1187 CandidateList minArgCost = findMinCost( matches ); 1188 promoteCvtCost( minArgCost ); 1189 candidates = findMinCost( minArgCost ); 1190 } 1191 1192 void Finder::postvisit( const ast::VirtualCastExpr * castExpr ) { 1193 assertf( castExpr->result, "Implicit virtual cast targets not yet supported." ); 1194 CandidateFinder finder( context, tenv ); 1195 // don't prune here, all alternatives guaranteed to have same type 1196 finder.find( castExpr->arg, ResolvMode::withoutPrune() ); 1197 for ( CandidateRef & r : finder.candidates ) { 1198 addCandidate( 1199 *r, 1200 new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } ); 1201 } 1202 } 1203 1204 void Finder::postvisit( const ast::KeywordCastExpr * castExpr ) { 1205 const auto & loc = castExpr->location; 1206 assertf( castExpr->result, "Cast target should have been set in Validate." ); 1207 auto ref = castExpr->result.strict_as<ast::ReferenceType>(); 1208 auto inst = ref->base.strict_as<ast::StructInstType>(); 1209 auto target = inst->base.get(); 1210 1211 CandidateFinder finder( context, tenv ); 1212 1213 auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) { 1214 for (auto & cand : found) { 1215 const ast::Type * expr = cand->expr->result.get(); 1216 if (expect_ref) { 1217 auto res = dynamic_cast<const ast::ReferenceType*>(expr); 1218 if (!res) { continue; } 1219 expr = res->base.get(); 1220 } 1221 1222 if (auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) { 1223 auto td = cand->env.lookup(*insttype); 1224 if (!td) { continue; } 1225 expr = td->bound.get(); 1226 } 1227 1228 if (auto base = dynamic_cast<const ast::StructInstType*>(expr)) { 1229 if (base->base == target) { 1230 candidates.push_back( std::move(cand) ); 1231 reason.code = NoReason; 1232 } 1233 } 1234 } 1235 }; 1236 1237 try { 1238 // Attempt 1 : turn (thread&)X into (thread$&)X.__thrd 1239 // Clone is purely for memory management 1240 std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) }; 1241 1242 // don't prune here, since it's guaranteed all alternatives will have the same type 1243 finder.find( tech1.get(), ResolvMode::withoutPrune() ); 1244 pick_alternatives(finder.candidates, false); 1245 1246 return; 1247 } catch(SemanticErrorException & ) {} 1248 1249 // Fallback : turn (thread&)X into (thread$&)get_thread(X) 1250 std::unique_ptr<const ast::Expr> fallback { ast::UntypedExpr::createDeref(loc, new ast::UntypedExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.getter), { castExpr->arg })) }; 1251 // don't prune here, since it's guaranteed all alternatives will have the same type 1252 finder.find( fallback.get(), ResolvMode::withoutPrune() ); 1253 1254 pick_alternatives(finder.candidates, true); 1255 1256 // Whatever happens here, we have no more fallbacks 1257 } 1258 1259 void Finder::postvisit( const ast::UntypedMemberExpr * memberExpr ) { 1260 CandidateFinder aggFinder( context, tenv ); 1261 aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() ); 1262 for ( CandidateRef & agg : aggFinder.candidates ) { 1263 // it's okay for the aggregate expression to have reference type -- cast it to the 1264 // base type to treat the aggregate as the referenced value 1265 Cost addedCost = Cost::zero; 1266 agg->expr = referenceToRvalueConversion( agg->expr, addedCost ); 1267 1268 // find member of the given type 1269 if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) { 1270 addAggMembers( 1271 structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1272 } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) { 1273 addAggMembers( 1274 unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1275 } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) { 1276 addTupleMembers( tupleType, agg->expr, *agg, addedCost, memberExpr->member ); 1277 } 1278 } 1279 } 1280 1281 void Finder::postvisit( const ast::MemberExpr * memberExpr ) { 1282 addCandidate( memberExpr, tenv ); 1283 } 1284 1285 void Finder::postvisit( const ast::NameExpr * nameExpr ) { 1286 std::vector< ast::SymbolTable::IdData > declList; 1287 if (!selfFinder.otypeKeys.empty()) { 1288 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name); 1289 assertf(kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS, "special lookup with non-special target: %s", nameExpr->name.c_str()); 1290 1291 for (auto & otypeKey: selfFinder.otypeKeys) { 1292 auto result = symtab.specialLookupId(kind, otypeKey); 1293 declList.insert(declList.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end())); 1294 } 1295 } else { 1296 declList = symtab.lookupId( nameExpr->name ); 1297 } 1298 PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; ) 1299 1300 if ( declList.empty() ) return; 1301 1302 reason.code = NoMatch; 1303 1304 for ( auto & data : declList ) { 1305 Cost cost = Cost::zero; 1306 ast::Expr * newExpr = data.combine( nameExpr->location, cost ); 1307 1308 CandidateRef newCand = std::make_shared<Candidate>( 1309 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1310 cost ); 1311 1312 if (newCand->expr->env) { 1313 newCand->env.add(*newCand->expr->env); 1314 auto mutExpr = newCand->expr.get_and_mutate(); 1315 mutExpr->env = nullptr; 1316 newCand->expr = mutExpr; 1317 } 1318 1319 PRINT( 1320 std::cerr << "decl is "; 1321 ast::print( std::cerr, data.id ); 1322 std::cerr << std::endl; 1323 std::cerr << "newExpr is "; 1324 ast::print( std::cerr, newExpr ); 1325 std::cerr << std::endl; 1326 ) 1327 newCand->expr = ast::mutate_field( 1328 newCand->expr.get(), &ast::Expr::result, 1329 renameTyVars( newCand->expr->result ) ); 1330 // add anonymous member interpretations whenever an aggregate value type is seen 1331 // as a name expression 1332 addAnonConversions( newCand ); 1333 candidates.emplace_back( std::move( newCand ) ); 1334 } 1335 } 1336 1337 void Finder::postvisit( const ast::VariableExpr * variableExpr ) { 1338 // not sufficient to just pass `variableExpr` here, type might have changed since 1339 // creation 1340 addCandidate( 1341 new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv ); 1342 } 1343 1344 void Finder::postvisit( const ast::ConstantExpr * constantExpr ) { 1345 addCandidate( constantExpr, tenv ); 1346 } 1347 1348 void Finder::postvisit( const ast::SizeofExpr * sizeofExpr ) { 1349 if ( sizeofExpr->type ) { 1350 addCandidate( 1351 new ast::SizeofExpr{ 1352 sizeofExpr->location, resolveTypeof( sizeofExpr->type, context ) }, 1353 tenv ); 1354 } else { 1355 // find all candidates for the argument to sizeof 1356 CandidateFinder finder( context, tenv ); 1357 finder.find( sizeofExpr->expr ); 1358 // find the lowest-cost candidate, otherwise ambiguous 1359 CandidateList winners = findMinCost( finder.candidates ); 1360 if ( winners.size() != 1 ) { 1361 SemanticError( 1362 sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " ); 1363 } 1364 // return the lowest-cost candidate 1365 CandidateRef & choice = winners.front(); 1366 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost ); 1367 choice->cost = Cost::zero; 1368 addCandidate( *choice, new ast::SizeofExpr{ sizeofExpr->location, choice->expr } ); 1369 } 1370 } 1371 1372 void Finder::postvisit( const ast::AlignofExpr * alignofExpr ) { 1373 if ( alignofExpr->type ) { 1374 addCandidate( 1375 new ast::AlignofExpr{ 1376 alignofExpr->location, resolveTypeof( alignofExpr->type, context ) }, 1377 tenv ); 1378 } else { 1379 // find all candidates for the argument to alignof 1380 CandidateFinder finder( context, tenv ); 1381 finder.find( alignofExpr->expr ); 1382 // find the lowest-cost candidate, otherwise ambiguous 1383 CandidateList winners = findMinCost( finder.candidates ); 1384 if ( winners.size() != 1 ) { 1385 SemanticError( 1386 alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " ); 1387 } 1388 // return the lowest-cost candidate 1389 CandidateRef & choice = winners.front(); 1390 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost ); 1391 choice->cost = Cost::zero; 1392 addCandidate( 1393 *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } ); 1394 } 1395 } 1396 1397 void Finder::postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) { 1398 const ast::BaseInstType * aggInst; 1399 if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ; 1400 else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ; 1401 else return; 1402 1403 for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) { 1404 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member ); 1405 addCandidate( 1406 new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv ); 1407 } 1408 } 1409 1410 void Finder::postvisit( const ast::OffsetofExpr * offsetofExpr ) { 1411 addCandidate( offsetofExpr, tenv ); 1412 } 1413 1414 void Finder::postvisit( const ast::OffsetPackExpr * offsetPackExpr ) { 1415 addCandidate( offsetPackExpr, tenv ); 1416 } 1417 1418 void Finder::postvisit( const ast::LogicalExpr * logicalExpr ) { 1419 CandidateFinder finder1( context, tenv ); 1420 finder1.find( logicalExpr->arg1, ResolvMode::withAdjustment() ); 1421 if ( finder1.candidates.empty() ) return; 1422 1423 CandidateFinder finder2( context, tenv ); 1424 finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() ); 1425 if ( finder2.candidates.empty() ) return; 1426 1427 reason.code = NoMatch; 1428 1429 for ( const CandidateRef & r1 : finder1.candidates ) { 1430 for ( const CandidateRef & r2 : finder2.candidates ) { 1431 ast::TypeEnvironment env{ r1->env }; 1432 env.simpleCombine( r2->env ); 1433 ast::OpenVarSet open{ r1->open }; 1434 mergeOpenVars( open, r2->open ); 1435 ast::AssertionSet need; 1436 mergeAssertionSet( need, r1->need ); 1437 mergeAssertionSet( need, r2->need ); 1438 1439 addCandidate( 1440 new ast::LogicalExpr{ 1441 logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd }, 1442 std::move( env ), std::move( open ), std::move( need ), r1->cost + r2->cost ); 1443 } 1444 } 1445 } 1446 1447 void Finder::postvisit( const ast::ConditionalExpr * conditionalExpr ) { 1448 // candidates for condition 1449 CandidateFinder finder1( context, tenv ); 1450 finder1.find( conditionalExpr->arg1, ResolvMode::withAdjustment() ); 1451 if ( finder1.candidates.empty() ) return; 1452 1453 // candidates for true result 1454 CandidateFinder finder2( context, tenv ); 1455 finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() ); 1456 if ( finder2.candidates.empty() ) return; 1457 1458 // candidates for false result 1459 CandidateFinder finder3( context, tenv ); 1460 finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() ); 1461 if ( finder3.candidates.empty() ) return; 1462 1463 reason.code = NoMatch; 1464 1465 for ( const CandidateRef & r1 : finder1.candidates ) { 1466 for ( const CandidateRef & r2 : finder2.candidates ) { 1467 for ( const CandidateRef & r3 : finder3.candidates ) { 1468 ast::TypeEnvironment env{ r1->env }; 1469 env.simpleCombine( r2->env ); 1470 env.simpleCombine( r3->env ); 1471 ast::OpenVarSet open{ r1->open }; 1472 mergeOpenVars( open, r2->open ); 1473 mergeOpenVars( open, r3->open ); 1474 ast::AssertionSet need; 1475 mergeAssertionSet( need, r1->need ); 1476 mergeAssertionSet( need, r2->need ); 1477 mergeAssertionSet( need, r3->need ); 1478 ast::AssertionSet have; 1479 1480 // unify true and false results, then infer parameters to produce new 1481 // candidates 1482 ast::ptr< ast::Type > common; 1483 if ( 1484 unify( 1485 r2->expr->result, r3->expr->result, env, need, have, open, 1486 common ) 1487 ) { 1488 // generate typed expression 1489 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1490 conditionalExpr->location, r1->expr, r2->expr, r3->expr }; 1491 newExpr->result = common ? common : r2->expr->result; 1492 // convert both options to result type 1493 Cost cost = r1->cost + r2->cost + r3->cost; 1494 newExpr->arg2 = computeExpressionConversionCost( 1495 newExpr->arg2, newExpr->result, symtab, env, cost ); 1496 newExpr->arg3 = computeExpressionConversionCost( 1497 newExpr->arg3, newExpr->result, symtab, env, cost ); 1498 // output candidate 1499 CandidateRef newCand = std::make_shared<Candidate>( 1500 newExpr, std::move( env ), std::move( open ), std::move( need ), cost ); 1501 inferParameters( newCand, candidates ); 1502 } 1503 } 1504 } 1505 } 1506 } 1507 1508 void Finder::postvisit( const ast::CommaExpr * commaExpr ) { 1509 ast::TypeEnvironment env{ tenv }; 1510 ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, context, env ); 1511 1512 CandidateFinder finder2( context, env ); 1513 finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() ); 1514 1515 for ( const CandidateRef & r2 : finder2.candidates ) { 1516 addCandidate( *r2, new ast::CommaExpr{ commaExpr->location, arg1, r2->expr } ); 1517 } 1518 } 1519 1520 void Finder::postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ) { 1521 addCandidate( ctorExpr, tenv ); 1522 } 1523 1524 void Finder::postvisit( const ast::ConstructorExpr * ctorExpr ) { 1525 CandidateFinder finder( context, tenv ); 1526 finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() ); 1527 for ( CandidateRef & r : finder.candidates ) { 1528 addCandidate( *r, new ast::ConstructorExpr{ ctorExpr->location, r->expr } ); 1529 } 1530 } 1531 1532 void Finder::postvisit( const ast::RangeExpr * rangeExpr ) { 1533 // resolve low and high, accept candidates where low and high types unify 1534 CandidateFinder finder1( context, tenv ); 1535 finder1.find( rangeExpr->low, ResolvMode::withAdjustment() ); 1536 if ( finder1.candidates.empty() ) return; 1537 1538 CandidateFinder finder2( context, tenv ); 1539 finder2.find( rangeExpr->high, ResolvMode::withAdjustment() ); 1540 if ( finder2.candidates.empty() ) return; 1541 1542 reason.code = NoMatch; 1543 1544 for ( const CandidateRef & r1 : finder1.candidates ) { 1545 for ( const CandidateRef & r2 : finder2.candidates ) { 1546 ast::TypeEnvironment env{ r1->env }; 1547 env.simpleCombine( r2->env ); 1548 ast::OpenVarSet open{ r1->open }; 1549 mergeOpenVars( open, r2->open ); 1550 ast::AssertionSet need; 1551 mergeAssertionSet( need, r1->need ); 1552 mergeAssertionSet( need, r2->need ); 1553 ast::AssertionSet have; 1554 1555 ast::ptr< ast::Type > common; 1556 if ( 1557 unify( 1558 r1->expr->result, r2->expr->result, env, need, have, open, 1559 common ) 1560 ) { 1561 // generate new expression 1562 ast::RangeExpr * newExpr = 1563 new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr }; 1564 newExpr->result = common ? common : r1->expr->result; 1565 // add candidate 1566 CandidateRef newCand = std::make_shared<Candidate>( 1567 newExpr, std::move( env ), std::move( open ), std::move( need ), 1568 r1->cost + r2->cost ); 1569 inferParameters( newCand, candidates ); 1570 } 1571 } 1572 } 1573 } 1574 1575 void Finder::postvisit( const ast::UntypedTupleExpr * tupleExpr ) { 1576 std::vector< CandidateFinder > subCandidates = 1577 selfFinder.findSubExprs( tupleExpr->exprs ); 1578 std::vector< CandidateList > possibilities; 1579 combos( subCandidates.begin(), subCandidates.end(), back_inserter( possibilities ) ); 1580 1581 for ( const CandidateList & subs : possibilities ) { 1582 std::vector< ast::ptr< ast::Expr > > exprs; 1583 exprs.reserve( subs.size() ); 1584 for ( const CandidateRef & sub : subs ) { exprs.emplace_back( sub->expr ); } 1585 1586 ast::TypeEnvironment env; 1587 ast::OpenVarSet open; 1588 ast::AssertionSet need; 1589 for ( const CandidateRef & sub : subs ) { 1590 env.simpleCombine( sub->env ); 1591 mergeOpenVars( open, sub->open ); 1592 mergeAssertionSet( need, sub->need ); 1593 } 1594 1595 addCandidate( 1596 new ast::TupleExpr{ tupleExpr->location, std::move( exprs ) }, 1597 std::move( env ), std::move( open ), std::move( need ), sumCost( subs ) ); 1598 } 1599 } 1600 1601 void Finder::postvisit( const ast::TupleExpr * tupleExpr ) { 1602 addCandidate( tupleExpr, tenv ); 1603 } 1604 1605 void Finder::postvisit( const ast::TupleIndexExpr * tupleExpr ) { 1606 addCandidate( tupleExpr, tenv ); 1607 } 1608 1609 void Finder::postvisit( const ast::TupleAssignExpr * tupleExpr ) { 1610 addCandidate( tupleExpr, tenv ); 1611 } 1612 1613 void Finder::postvisit( const ast::UniqueExpr * unqExpr ) { 1614 CandidateFinder finder( context, tenv ); 1615 finder.find( unqExpr->expr, ResolvMode::withAdjustment() ); 1616 for ( CandidateRef & r : finder.candidates ) { 1617 // ensure that the the id is passed on so that the expressions are "linked" 1618 addCandidate( *r, new ast::UniqueExpr{ unqExpr->location, r->expr, unqExpr->id } ); 1619 } 1620 } 1621 1622 void Finder::postvisit( const ast::StmtExpr * stmtExpr ) { 1623 addCandidate( resolveStmtExpr( stmtExpr, context ), tenv ); 1624 } 1625 1626 void Finder::postvisit( const ast::UntypedInitExpr * initExpr ) { 1627 // handle each option like a cast 1628 CandidateList matches; 1629 PRINT( 1630 std::cerr << "untyped init expr: " << initExpr << std::endl; 1631 ) 1632 // O(n^2) checks of d-types with e-types 1633 for ( const ast::InitAlternative & initAlt : initExpr->initAlts ) { 1634 // calculate target type 1635 const ast::Type * toType = resolveTypeof( initAlt.type, context ); 1636 toType = adjustExprType( toType, tenv, symtab ); 1637 // The call to find must occur inside this loop, otherwise polymorphic return 1638 // types are not bound to the initialization type, since return type variables are 1639 // only open for the duration of resolving the UntypedExpr. 1640 CandidateFinder finder( context, tenv, toType ); 1641 finder.find( initExpr->expr, ResolvMode::withAdjustment() ); 1642 for ( CandidateRef & cand : finder.candidates ) { 1643 if (reason.code == NotFound) reason.code = NoMatch; 1644 1645 ast::TypeEnvironment env{ cand->env }; 1646 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have; 1647 ast::OpenVarSet open{ cand->open }; 1648 1649 PRINT( 1650 std::cerr << " @ " << toType << " " << initAlt.designation << std::endl; 1651 ) 1652 1653 // It is possible that a cast can throw away some values in a multiply-valued 1654 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 1655 // the subexpression results that are cast directly. The candidate is invalid 1656 // if it has fewer results than there are types to cast to. 1657 int discardedValues = cand->expr->result->size() - toType->size(); 1658 if ( discardedValues < 0 ) continue; 1659 1660 // unification run for side-effects 1661 bool canUnify = unify( toType, cand->expr->result, env, need, have, open ); 1662 (void) canUnify; 1663 Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1664 symtab, env ); 1665 PRINT( 1666 Cost legacyCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1667 symtab, env ); 1668 std::cerr << "Considering initialization:"; 1669 std::cerr << std::endl << " FROM: " << cand->expr->result << std::endl; 1670 std::cerr << std::endl << " TO: " << toType << std::endl; 1671 std::cerr << std::endl << " Unification " << (canUnify ? "succeeded" : "failed"); 1672 std::cerr << std::endl << " Legacy cost " << legacyCost; 1673 std::cerr << std::endl << " New cost " << thisCost; 1674 std::cerr << std::endl; 1675 ) 1676 if ( thisCost != Cost::infinity ) { 1677 // count one safe conversion for each value that is thrown away 1678 thisCost.incSafe( discardedValues ); 1679 CandidateRef newCand = std::make_shared<Candidate>( 1680 new ast::InitExpr{ 1681 initExpr->location, restructureCast( cand->expr, toType ), 1682 initAlt.designation }, 1683 std::move(env), std::move( open ), std::move( need ), cand->cost, thisCost ); 1684 inferParameters( newCand, matches ); 1685 } 1686 } 1687 } 1688 1689 // select first on argument cost, then conversion cost 1690 CandidateList minArgCost = findMinCost( matches ); 1691 promoteCvtCost( minArgCost ); 1692 candidates = findMinCost( minArgCost ); 1693 } 1694 1695 // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder"); 1696 /// Prunes a list of candidates down to those that have the minimum conversion cost for a given 1697 /// return type. Skips ambiguous candidates. 1698 1699 } // anonymous namespace 1700 1701 bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) { 1702 struct PruneStruct { 1703 CandidateRef candidate; 1704 bool ambiguous; 1705 1706 PruneStruct() = default; 1707 PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {} 1708 }; 1709 1710 // find lowest-cost candidate for each type 1711 std::unordered_map< std::string, PruneStruct > selected; 1712 // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found 1713 std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;}); 1714 for ( CandidateRef & candidate : candidates ) { 1715 std::string mangleName; 1716 { 1717 ast::ptr< ast::Type > newType = candidate->expr->result; 1718 assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get()); 1719 candidate->env.apply( newType ); 1720 mangleName = Mangle::mangle( newType ); 1721 } 1722 1723 auto found = selected.find( mangleName ); 1724 if (found != selected.end() && found->second.candidate->cost < candidate->cost) { 1725 PRINT( 1726 std::cerr << "cost " << candidate->cost << " loses to " 1727 << found->second.candidate->cost << std::endl; 1728 ) 1729 continue; 1730 } 1731 1732 // xxx - when do satisfyAssertions produce more than 1 result? 1733 // this should only happen when initial result type contains 1734 // unbound type parameters, then it should never be pruned by 1735 // the previous step, since renameTyVars guarantees the mangled name 1736 // is unique. 1737 CandidateList satisfied; 1738 bool needRecomputeKey = false; 1739 if (candidate->need.empty()) { 1740 satisfied.emplace_back(candidate); 1741 } 1742 else { 1743 satisfyAssertions(candidate, context.symtab, satisfied, errors); 1744 needRecomputeKey = true; 1745 } 1746 1747 for (auto & newCand : satisfied) { 1748 // recomputes type key, if satisfyAssertions changed it 1749 if (needRecomputeKey) 1750 { 1751 ast::ptr< ast::Type > newType = newCand->expr->result; 1752 assertf(newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get()); 1753 newCand->env.apply( newType ); 1754 mangleName = Mangle::mangle( newType ); 1755 } 1756 auto found = selected.find( mangleName ); 1757 if ( found != selected.end() ) { 1758 if ( newCand->cost < found->second.candidate->cost ) { 1759 PRINT( 1760 std::cerr << "cost " << newCand->cost << " beats " 1761 << found->second.candidate->cost << std::endl; 1762 ) 1763 1764 found->second = PruneStruct{ newCand }; 1765 } else if ( newCand->cost == found->second.candidate->cost ) { 1766 // if one of the candidates contains a deleted identifier, can pick the other, 1767 // since deleted expressions should not be ambiguous if there is another option 1768 // that is at least as good 1769 if ( findDeletedExpr( newCand->expr ) ) { 1770 // do nothing 1771 PRINT( std::cerr << "candidate is deleted" << std::endl; ) 1772 } else if ( findDeletedExpr( found->second.candidate->expr ) ) { 1773 PRINT( std::cerr << "current is deleted" << std::endl; ) 1774 found->second = PruneStruct{ newCand }; 1775 } else { 1776 PRINT( std::cerr << "marking ambiguous" << std::endl; ) 1777 found->second.ambiguous = true; 1778 } 1779 } else { 1780 // xxx - can satisfyAssertions increase the cost? 1781 PRINT( 1782 std::cerr << "cost " << newCand->cost << " loses to " 1783 << found->second.candidate->cost << std::endl; 1784 ) 1785 } 1786 } else { 1787 selected.emplace_hint( found, mangleName, newCand ); 1788 } 1789 } 1790 } 1791 1792 // report unambiguous min-cost candidates 1793 // CandidateList out; 1794 for ( auto & target : selected ) { 1795 if ( target.second.ambiguous ) continue; 1796 1797 CandidateRef cand = target.second.candidate; 1798 1799 ast::ptr< ast::Type > newResult = cand->expr->result; 1800 cand->env.applyFree( newResult ); 1801 cand->expr = ast::mutate_field( 1802 cand->expr.get(), &ast::Expr::result, std::move( newResult ) ); 1803 1804 out.emplace_back( cand ); 1805 } 1806 // if everything is lost in satisfyAssertions, report the error 1807 return !selected.empty(); 1808 } 1809 1810 void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) { 1811 // Find alternatives for expression 1812 ast::Pass<Finder> finder{ *this }; 1813 expr->accept( finder ); 1814 1815 if ( mode.failFast && candidates.empty() ) { 1816 switch(finder.core.reason.code) { 1817 case Finder::NotFound: 1818 { SemanticError( expr, "No alternatives for expression " ); break; } 1819 case Finder::NoMatch: 1820 { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; } 1821 case Finder::ArgsToFew: 1822 case Finder::ArgsToMany: 1823 case Finder::RetsToFew: 1824 case Finder::RetsToMany: 1825 case Finder::NoReason: 1826 default: 1827 { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); } 1828 } 1829 } 1830 1831 /* 1832 if ( mode.satisfyAssns || mode.prune ) { 1833 // trim candidates to just those where the assertions are satisfiable 1834 // - necessary pre-requisite to pruning 1835 CandidateList satisfied; 1836 std::vector< std::string > errors; 1837 for ( CandidateRef & candidate : candidates ) { 1838 satisfyAssertions( candidate, localSyms, satisfied, errors ); 1839 } 1840 1841 // fail early if none such 1842 if ( mode.failFast && satisfied.empty() ) { 1843 std::ostringstream stream; 1844 stream << "No alternatives with satisfiable assertions for " << expr << "\n"; 1845 for ( const auto& err : errors ) { 1846 stream << err; 1847 } 1848 SemanticError( expr->location, stream.str() ); 1849 } 1850 1851 // reset candidates 1852 candidates = move( satisfied ); 1853 } 1854 */ 1855 1856 if ( mode.prune ) { 1857 // trim candidates to single best one 1858 PRINT( 1859 std::cerr << "alternatives before prune:" << std::endl; 1860 print( std::cerr, candidates ); 1861 ) 1862 1863 CandidateList pruned; 1864 std::vector<std::string> errors; 1865 bool found = pruneCandidates( candidates, pruned, errors ); 1866 1867 if ( mode.failFast && pruned.empty() ) { 1868 std::ostringstream stream; 1869 if (found) { 1870 CandidateList winners = findMinCost( candidates ); 1871 stream << "Cannot choose between " << winners.size() << " alternatives for " 1872 "expression\n"; 1873 ast::print( stream, expr ); 1874 stream << " Alternatives are:\n"; 1875 print( stream, winners, 1 ); 1876 SemanticError( expr->location, stream.str() ); 1877 } 1878 else { 1879 stream << "No alternatives with satisfiable assertions for " << expr << "\n"; 1880 for ( const auto& err : errors ) { 1881 stream << err; 1882 } 1883 SemanticError( expr->location, stream.str() ); 1884 } 1885 } 1886 1887 auto oldsize = candidates.size(); 1888 candidates = std::move( pruned ); 1889 1890 PRINT( 1891 std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl; 1892 ) 1893 PRINT( 1894 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1895 << std::endl; 1896 ) 1897 } 1898 1899 // adjust types after pruning so that types substituted by pruneAlternatives are correctly 1900 // adjusted 1901 if ( mode.adjust ) { 1902 for ( CandidateRef & r : candidates ) { 1903 r->expr = ast::mutate_field( 1904 r->expr.get(), &ast::Expr::result, 1905 adjustExprType( r->expr->result, r->env, context.symtab ) ); 1906 } 1907 } 1908 1909 // Central location to handle gcc extension keyword, etc. for all expressions 1910 for ( CandidateRef & r : candidates ) { 1911 if ( r->expr->extension != expr->extension ) { 1912 r->expr.get_and_mutate()->extension = expr->extension; 1913 } 1914 } 1915 } 1916 1917 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1918 const std::vector< ast::ptr< ast::Expr > > & xs 1919 ) { 1920 std::vector< CandidateFinder > out; 1921 1922 for ( const auto & x : xs ) { 1923 out.emplace_back( context, env ); 1924 out.back().find( x, ResolvMode::withAdjustment() ); 1925 1926 PRINT( 1927 std::cerr << "findSubExprs" << std::endl; 1928 print( std::cerr, out.back().candidates ); 1929 ) 1930 } 1931 1932 return out; 1933 } 1934 58 1935 const ast::Expr * referenceToRvalueConversion( const ast::Expr * expr, Cost & cost ) { 59 1936 if ( expr->result.as< ast::ReferenceType >() ) { … … 65 1942 return expr; 66 1943 } 67 68 /// Unique identifier for matching expression resolutions to their requesting expression69 UniqueId globalResnSlot = 0;70 1944 71 1945 Cost computeConversionCost( … … 94 1968 } 95 1969 96 namespace {97 /// First index is which argument, second is which alternative, third is which exploded element98 using ExplodedArgs_new = std::deque< std::vector< ExplodedArg > >;99 100 /// Returns a list of alternatives with the minimum cost in the given list101 CandidateList findMinCost( const CandidateList & candidates ) {102 CandidateList out;103 Cost minCost = Cost::infinity;104 for ( const CandidateRef & r : candidates ) {105 if ( r->cost < minCost ) {106 minCost = r->cost;107 out.clear();108 out.emplace_back( r );109 } else if ( r->cost == minCost ) {110 out.emplace_back( r );111 }112 }113 return out;114 }115 116 /// Computes conversion cost for a given expression to a given type117 const ast::Expr * computeExpressionConversionCost(118 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost119 ) {120 Cost convCost = computeConversionCost(121 arg->result, paramType, arg->get_lvalue(), symtab, env );122 outCost += convCost;123 124 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires125 // conversion. Ignore poly cost for now, since this requires resolution of the cast to126 // infer parameters and this does not currently work for the reason stated below127 Cost tmpCost = convCost;128 tmpCost.incPoly( -tmpCost.get_polyCost() );129 if ( tmpCost != Cost::zero ) {130 ast::ptr< ast::Type > newType = paramType;131 env.apply( newType );132 return new ast::CastExpr{ arg, newType };133 134 // xxx - *should* be able to resolve this cast, but at the moment pointers are not135 // castable to zero_t, but are implicitly convertible. This is clearly inconsistent,136 // once this is fixed it should be possible to resolve the cast.137 // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable,138 // but it shouldn't be because this makes the conversion from DT* to DT* since139 // commontype(zero_t, DT*) is DT*, rather than nothing140 141 // CandidateFinder finder{ symtab, env };142 // finder.find( arg, ResolvMode::withAdjustment() );143 // assertf( finder.candidates.size() > 0,144 // "Somehow castable expression failed to find alternatives." );145 // assertf( finder.candidates.size() == 1,146 // "Somehow got multiple alternatives for known cast expression." );147 // return finder.candidates.front()->expr;148 }149 150 return arg;151 }152 153 /// Computes conversion cost for a given candidate154 Cost computeApplicationConversionCost(155 CandidateRef cand, const ast::SymbolTable & symtab156 ) {157 auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >();158 auto pointer = appExpr->func->result.strict_as< ast::PointerType >();159 auto function = pointer->base.strict_as< ast::FunctionType >();160 161 Cost convCost = Cost::zero;162 const auto & params = function->params;163 auto param = params.begin();164 auto & args = appExpr->args;165 166 for ( unsigned i = 0; i < args.size(); ++i ) {167 const ast::Type * argType = args[i]->result;168 PRINT(169 std::cerr << "arg expression:" << std::endl;170 ast::print( std::cerr, args[i], 2 );171 std::cerr << "--- results are" << std::endl;172 ast::print( std::cerr, argType, 2 );173 )174 175 if ( param == params.end() ) {176 if ( function->isVarArgs ) {177 convCost.incUnsafe();178 PRINT( std::cerr << "end of params with varargs function: inc unsafe: "179 << convCost << std::endl; ; )180 // convert reference-typed expressions into value-typed expressions181 cand->expr = ast::mutate_field_index(182 appExpr, &ast::ApplicationExpr::args, i,183 referenceToRvalueConversion( args[i], convCost ) );184 continue;185 } else return Cost::infinity;186 }187 188 if ( auto def = args[i].as< ast::DefaultArgExpr >() ) {189 // Default arguments should be free - don't include conversion cost.190 // Unwrap them here because they are not relevant to the rest of the system191 cand->expr = ast::mutate_field_index(192 appExpr, &ast::ApplicationExpr::args, i, def->expr );193 ++param;194 continue;195 }196 197 // mark conversion cost and also specialization cost of param type198 // const ast::Type * paramType = (*param)->get_type();199 cand->expr = ast::mutate_field_index(200 appExpr, &ast::ApplicationExpr::args, i,201 computeExpressionConversionCost(202 args[i], *param, symtab, cand->env, convCost ) );203 convCost.decSpec( specCost( *param ) );204 ++param; // can't be in for-loop update because of the continue205 }206 207 if ( param != params.end() ) return Cost::infinity;208 209 // specialization cost of return types can't be accounted for directly, it disables210 // otherwise-identical calls, like this example based on auto-newline in the I/O lib:211 //212 // forall(otype OS) {213 // void ?|?(OS&, int); // with newline214 // OS& ?|?(OS&, int); // no newline, always chosen due to more specialization215 // }216 217 // mark type variable and specialization cost of forall clause218 convCost.incVar( function->forall.size() );219 convCost.decSpec( function->assertions.size() );220 221 return convCost;222 }223 224 void makeUnifiableVars(225 const ast::FunctionType * type, ast::OpenVarSet & unifiableVars,226 ast::AssertionSet & need227 ) {228 for ( auto & tyvar : type->forall ) {229 unifiableVars[ *tyvar ] = ast::TypeData{ tyvar->base };230 }231 for ( auto & assn : type->assertions ) {232 need[ assn ].isUsed = true;233 }234 }235 236 /// Gets a default value from an initializer, nullptr if not present237 const ast::ConstantExpr * getDefaultValue( const ast::Init * init ) {238 if ( auto si = dynamic_cast< const ast::SingleInit * >( init ) ) {239 if ( auto ce = si->value.as< ast::CastExpr >() ) {240 return ce->arg.as< ast::ConstantExpr >();241 } else {242 return si->value.as< ast::ConstantExpr >();243 }244 }245 return nullptr;246 }247 248 /// State to iteratively build a match of parameter expressions to arguments249 struct ArgPack {250 std::size_t parent; ///< Index of parent pack251 ast::ptr< ast::Expr > expr; ///< The argument stored here252 Cost cost; ///< The cost of this argument253 ast::TypeEnvironment env; ///< Environment for this pack254 ast::AssertionSet need; ///< Assertions outstanding for this pack255 ast::AssertionSet have; ///< Assertions found for this pack256 ast::OpenVarSet open; ///< Open variables for this pack257 unsigned nextArg; ///< Index of next argument in arguments list258 unsigned tupleStart; ///< Number of tuples that start at this index259 unsigned nextExpl; ///< Index of next exploded element260 unsigned explAlt; ///< Index of alternative for nextExpl > 0261 262 ArgPack()263 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ),264 tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}265 266 ArgPack(267 const ast::TypeEnvironment & env, const ast::AssertionSet & need,268 const ast::AssertionSet & have, const ast::OpenVarSet & open )269 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),270 open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}271 272 ArgPack(273 std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,274 ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,275 unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,276 unsigned nextExpl = 0, unsigned explAlt = 0 )277 : parent(parent), expr( expr ), cost( cost ), env( std::move( env ) ), need( std::move( need ) ),278 have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),279 nextExpl( nextExpl ), explAlt( explAlt ) {}280 281 ArgPack(282 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need,283 ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added )284 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( std::move( env ) ),285 need( std::move( need ) ), have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ),286 tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {}287 288 /// true if this pack is in the middle of an exploded argument289 bool hasExpl() const { return nextExpl > 0; }290 291 /// Gets the list of exploded candidates for this pack292 const ExplodedArg & getExpl( const ExplodedArgs_new & args ) const {293 return args[ nextArg-1 ][ explAlt ];294 }295 296 /// Ends a tuple expression, consolidating the appropriate args297 void endTuple( const std::vector< ArgPack > & packs ) {298 // add all expressions in tuple to list, summing cost299 std::deque< const ast::Expr * > exprs;300 const ArgPack * pack = this;301 if ( expr ) { exprs.emplace_front( expr ); }302 while ( pack->tupleStart == 0 ) {303 pack = &packs[pack->parent];304 exprs.emplace_front( pack->expr );305 cost += pack->cost;306 }307 // reset pack to appropriate tuple308 std::vector< ast::ptr< ast::Expr > > exprv( exprs.begin(), exprs.end() );309 expr = new ast::TupleExpr{ expr->location, std::move( exprv ) };310 tupleStart = pack->tupleStart - 1;311 parent = pack->parent;312 }313 };314 315 /// Instantiates an argument to match a parameter, returns false if no matching results left316 bool instantiateArgument(317 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args,318 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,319 unsigned nTuples = 0320 ) {321 if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) {322 // paramType is a TupleType -- group args into a TupleExpr323 ++nTuples;324 for ( const ast::Type * type : *tupleType ) {325 // xxx - dropping initializer changes behaviour from previous, but seems correct326 // ^^^ need to handle the case where a tuple has a default argument327 if ( ! instantiateArgument(328 type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;329 nTuples = 0;330 }331 // re-constitute tuples for final generation332 for ( auto i = genStart; i < results.size(); ++i ) {333 results[i].endTuple( results );334 }335 return true;336 } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) {337 // paramType is a ttype, consumes all remaining arguments338 339 // completed tuples; will be spliced to end of results to finish340 std::vector< ArgPack > finalResults{};341 342 // iterate until all results completed343 std::size_t genEnd;344 ++nTuples;345 do {346 genEnd = results.size();347 348 // add another argument to results349 for ( std::size_t i = genStart; i < genEnd; ++i ) {350 unsigned nextArg = results[i].nextArg;351 352 // use next element of exploded tuple if present353 if ( results[i].hasExpl() ) {354 const ExplodedArg & expl = results[i].getExpl( args );355 356 unsigned nextExpl = results[i].nextExpl + 1;357 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }358 359 results.emplace_back(360 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),361 copy( results[i].need ), copy( results[i].have ),362 copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl,363 results[i].explAlt );364 365 continue;366 }367 368 // finish result when out of arguments369 if ( nextArg >= args.size() ) {370 ArgPack newResult{371 results[i].env, results[i].need, results[i].have, results[i].open };372 newResult.nextArg = nextArg;373 const ast::Type * argType = nullptr;374 375 if ( nTuples > 0 || ! results[i].expr ) {376 // first iteration or no expression to clone,377 // push empty tuple expression378 newResult.parent = i;379 newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} };380 argType = newResult.expr->result;381 } else {382 // clone result to collect tuple383 newResult.parent = results[i].parent;384 newResult.cost = results[i].cost;385 newResult.tupleStart = results[i].tupleStart;386 newResult.expr = results[i].expr;387 argType = newResult.expr->result;388 389 if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) {390 // the case where a ttype value is passed directly is special,391 // e.g. for argument forwarding purposes392 // xxx - what if passing multiple arguments, last of which is393 // ttype?394 // xxx - what would happen if unify was changed so that unifying395 // tuple396 // types flattened both before unifying lists? then pass in397 // TupleType (ttype) below.398 --newResult.tupleStart;399 } else {400 // collapse leftover arguments into tuple401 newResult.endTuple( results );402 argType = newResult.expr->result;403 }404 }405 406 // check unification for ttype before adding to final407 if (408 unify(409 ttype, argType, newResult.env, newResult.need, newResult.have,410 newResult.open )411 ) {412 finalResults.emplace_back( std::move( newResult ) );413 }414 415 continue;416 }417 418 // add each possible next argument419 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {420 const ExplodedArg & expl = args[nextArg][j];421 422 // fresh copies of parent parameters for this iteration423 ast::TypeEnvironment env = results[i].env;424 ast::OpenVarSet open = results[i].open;425 426 env.addActual( expl.env, open );427 428 // skip empty tuple arguments by (nearly) cloning parent into next gen429 if ( expl.exprs.empty() ) {430 results.emplace_back(431 results[i], std::move( env ), copy( results[i].need ),432 copy( results[i].have ), std::move( open ), nextArg + 1, expl.cost );433 434 continue;435 }436 437 // add new result438 results.emplace_back(439 i, expl.exprs.front(), std::move( env ), copy( results[i].need ),440 copy( results[i].have ), std::move( open ), nextArg + 1, nTuples,441 expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );442 }443 }444 445 // reset for next round446 genStart = genEnd;447 nTuples = 0;448 } while ( genEnd != results.size() );449 450 // splice final results onto results451 for ( std::size_t i = 0; i < finalResults.size(); ++i ) {452 results.emplace_back( std::move( finalResults[i] ) );453 }454 return ! finalResults.empty();455 }456 457 // iterate each current subresult458 std::size_t genEnd = results.size();459 for ( std::size_t i = genStart; i < genEnd; ++i ) {460 unsigned nextArg = results[i].nextArg;461 462 // use remainder of exploded tuple if present463 if ( results[i].hasExpl() ) {464 const ExplodedArg & expl = results[i].getExpl( args );465 const ast::Expr * expr = expl.exprs[ results[i].nextExpl ];466 467 ast::TypeEnvironment env = results[i].env;468 ast::AssertionSet need = results[i].need, have = results[i].have;469 ast::OpenVarSet open = results[i].open;470 471 const ast::Type * argType = expr->result;472 473 PRINT(474 std::cerr << "param type is ";475 ast::print( std::cerr, paramType );476 std::cerr << std::endl << "arg type is ";477 ast::print( std::cerr, argType );478 std::cerr << std::endl;479 )480 481 if ( unify( paramType, argType, env, need, have, open ) ) {482 unsigned nextExpl = results[i].nextExpl + 1;483 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }484 485 results.emplace_back(486 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), nextArg,487 nTuples, Cost::zero, nextExpl, results[i].explAlt );488 }489 490 continue;491 }492 493 // use default initializers if out of arguments494 if ( nextArg >= args.size() ) {495 if ( const ast::ConstantExpr * cnst = getDefaultValue( init ) ) {496 ast::TypeEnvironment env = results[i].env;497 ast::AssertionSet need = results[i].need, have = results[i].have;498 ast::OpenVarSet open = results[i].open;499 500 if ( unify( paramType, cnst->result, env, need, have, open ) ) {501 results.emplace_back(502 i, new ast::DefaultArgExpr{ cnst->location, cnst }, std::move( env ),503 std::move( need ), std::move( have ), std::move( open ), nextArg, nTuples );504 }505 }506 507 continue;508 }509 510 // Check each possible next argument511 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {512 const ExplodedArg & expl = args[nextArg][j];513 514 // fresh copies of parent parameters for this iteration515 ast::TypeEnvironment env = results[i].env;516 ast::AssertionSet need = results[i].need, have = results[i].have;517 ast::OpenVarSet open = results[i].open;518 519 env.addActual( expl.env, open );520 521 // skip empty tuple arguments by (nearly) cloning parent into next gen522 if ( expl.exprs.empty() ) {523 results.emplace_back(524 results[i], std::move( env ), std::move( need ), std::move( have ), std::move( open ),525 nextArg + 1, expl.cost );526 527 continue;528 }529 530 // consider only first exploded arg531 const ast::Expr * expr = expl.exprs.front();532 const ast::Type * argType = expr->result;533 534 PRINT(535 std::cerr << "param type is ";536 ast::print( std::cerr, paramType );537 std::cerr << std::endl << "arg type is ";538 ast::print( std::cerr, argType );539 std::cerr << std::endl;540 )541 542 // attempt to unify types543 if ( unify( paramType, argType, env, need, have, open ) ) {544 // add new result545 results.emplace_back(546 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),547 nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );548 }549 }550 }551 552 // reset for next parameter553 genStart = genEnd;554 555 return genEnd != results.size(); // were any new results added?556 }557 558 /// Generate a cast expression from `arg` to `toType`559 const ast::Expr * restructureCast(560 ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast561 ) {562 if (563 arg->result->size() > 1564 && ! toType->isVoid()565 && ! dynamic_cast< const ast::ReferenceType * >( toType )566 ) {567 // Argument is a tuple and the target type is neither void nor a reference. Cast each568 // member of the tuple to its corresponding target type, producing the tuple of those569 // cast expressions. If there are more components of the tuple than components in the570 // target type, then excess components do not come out in the result expression (but571 // UniqueExpr ensures that the side effects will still be produced)572 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {573 // expressions which may contain side effects require a single unique instance of574 // the expression575 arg = new ast::UniqueExpr{ arg->location, arg };576 }577 std::vector< ast::ptr< ast::Expr > > components;578 for ( unsigned i = 0; i < toType->size(); ++i ) {579 // cast each component580 ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i };581 components.emplace_back(582 restructureCast( idx, toType->getComponent( i ), isGenerated ) );583 }584 return new ast::TupleExpr{ arg->location, std::move( components ) };585 } else {586 // handle normally587 return new ast::CastExpr{ arg->location, arg, toType, isGenerated };588 }589 }590 591 /// Gets the name from an untyped member expression (must be NameExpr)592 const std::string & getMemberName( const ast::UntypedMemberExpr * memberExpr ) {593 if ( memberExpr->member.as< ast::ConstantExpr >() ) {594 SemanticError( memberExpr, "Indexed access to struct fields unsupported: " );595 }596 597 return memberExpr->member.strict_as< ast::NameExpr >()->name;598 }599 600 /// Actually visits expressions to find their candidate interpretations601 class Finder final : public ast::WithShortCircuiting {602 const ResolveContext & context;603 const ast::SymbolTable & symtab;604 public:605 // static size_t traceId;606 CandidateFinder & selfFinder;607 CandidateList & candidates;608 const ast::TypeEnvironment & tenv;609 ast::ptr< ast::Type > & targetType;610 611 enum Errors {612 NotFound,613 NoMatch,614 ArgsToFew,615 ArgsToMany,616 RetsToFew,617 RetsToMany,618 NoReason619 };620 621 struct {622 Errors code = NotFound;623 } reason;624 625 Finder( CandidateFinder & f )626 : context( f.context ), symtab( context.symtab ), selfFinder( f ),627 candidates( f.candidates ), tenv( f.env ), targetType( f.targetType ) {}628 629 void previsit( const ast::Node * ) { visit_children = false; }630 631 /// Convenience to add candidate to list632 template<typename... Args>633 void addCandidate( Args &&... args ) {634 candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } );635 reason.code = NoReason;636 }637 638 void postvisit( const ast::ApplicationExpr * applicationExpr ) {639 addCandidate( applicationExpr, tenv );640 }641 642 /// Set up candidate assertions for inference643 void inferParameters( CandidateRef & newCand, CandidateList & out ) {644 // Set need bindings for any unbound assertions645 UniqueId crntResnSlot = 0; // matching ID for this expression's assertions646 for ( auto & assn : newCand->need ) {647 // skip already-matched assertions648 if ( assn.second.resnSlot != 0 ) continue;649 // assign slot for expression if needed650 if ( crntResnSlot == 0 ) { crntResnSlot = ++globalResnSlot; }651 // fix slot to assertion652 assn.second.resnSlot = crntResnSlot;653 }654 // pair slot to expression655 if ( crntResnSlot != 0 ) {656 newCand->expr.get_and_mutate()->inferred.resnSlots().emplace_back( crntResnSlot );657 }658 659 // add to output list; assertion satisfaction will occur later660 out.emplace_back( newCand );661 }662 663 /// Completes a function candidate with arguments located664 void validateFunctionCandidate(665 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,666 CandidateList & out667 ) {668 ast::ApplicationExpr * appExpr =669 new ast::ApplicationExpr{ func->expr->location, func->expr };670 // sum cost and accumulate arguments671 std::deque< const ast::Expr * > args;672 Cost cost = func->cost;673 const ArgPack * pack = &result;674 while ( pack->expr ) {675 args.emplace_front( pack->expr );676 cost += pack->cost;677 pack = &results[pack->parent];678 }679 std::vector< ast::ptr< ast::Expr > > vargs( args.begin(), args.end() );680 appExpr->args = std::move( vargs );681 // build and validate new candidate682 auto newCand =683 std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost );684 PRINT(685 std::cerr << "instantiate function success: " << appExpr << std::endl;686 std::cerr << "need assertions:" << std::endl;687 ast::print( std::cerr, result.need, 2 );688 )689 inferParameters( newCand, out );690 }691 692 /// Builds a list of candidates for a function, storing them in out693 void makeFunctionCandidates(694 const CandidateRef & func, const ast::FunctionType * funcType,695 const ExplodedArgs_new & args, CandidateList & out696 ) {697 ast::OpenVarSet funcOpen;698 ast::AssertionSet funcNeed, funcHave;699 ast::TypeEnvironment funcEnv{ func->env };700 makeUnifiableVars( funcType, funcOpen, funcNeed );701 // add all type variables as open variables now so that those not used in the702 // parameter list are still considered open703 funcEnv.add( funcType->forall );704 705 if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) {706 // attempt to narrow based on expected target type707 const ast::Type * returnType = funcType->returns.front();708 if ( selfFinder.strictMode ) {709 if ( ! unifyExact(710 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, noWiden() ) // xxx - is no widening correct?711 ) {712 // unification failed, do not pursue this candidate713 return;714 }715 }716 else {717 if ( ! unify(718 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen )719 ) {720 // unification failed, do not pursue this candidate721 return;722 }723 }724 }725 726 // iteratively build matches, one parameter at a time727 std::vector< ArgPack > results;728 results.emplace_back( funcEnv, funcNeed, funcHave, funcOpen );729 std::size_t genStart = 0;730 731 // xxx - how to handle default arg after change to ftype representation?732 if (const ast::VariableExpr * varExpr = func->expr.as<ast::VariableExpr>()) {733 if (const ast::FunctionDecl * funcDecl = varExpr->var.as<ast::FunctionDecl>()) {734 // function may have default args only if directly calling by name735 // must use types on candidate however, due to RenameVars substitution736 auto nParams = funcType->params.size();737 738 for (size_t i=0; i<nParams; ++i) {739 auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>();740 if (!instantiateArgument(741 funcType->params[i], obj->init, args, results, genStart, symtab)) return;742 }743 goto endMatch;744 }745 }746 for ( const auto & param : funcType->params ) {747 // Try adding the arguments corresponding to the current parameter to the existing748 // matches749 // no default args for indirect calls750 if ( ! instantiateArgument(751 param, nullptr, args, results, genStart, symtab ) ) return;752 }753 754 endMatch:755 if ( funcType->isVarArgs ) {756 // append any unused arguments to vararg pack757 std::size_t genEnd;758 do {759 genEnd = results.size();760 761 // iterate results762 for ( std::size_t i = genStart; i < genEnd; ++i ) {763 unsigned nextArg = results[i].nextArg;764 765 // use remainder of exploded tuple if present766 if ( results[i].hasExpl() ) {767 const ExplodedArg & expl = results[i].getExpl( args );768 769 unsigned nextExpl = results[i].nextExpl + 1;770 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }771 772 results.emplace_back(773 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),774 copy( results[i].need ), copy( results[i].have ),775 copy( results[i].open ), nextArg, 0, Cost::zero, nextExpl,776 results[i].explAlt );777 778 continue;779 }780 781 // finish result when out of arguments782 if ( nextArg >= args.size() ) {783 validateFunctionCandidate( func, results[i], results, out );784 785 continue;786 }787 788 // add each possible next argument789 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {790 const ExplodedArg & expl = args[nextArg][j];791 792 // fresh copies of parent parameters for this iteration793 ast::TypeEnvironment env = results[i].env;794 ast::OpenVarSet open = results[i].open;795 796 env.addActual( expl.env, open );797 798 // skip empty tuple arguments by (nearly) cloning parent into next gen799 if ( expl.exprs.empty() ) {800 results.emplace_back(801 results[i], std::move( env ), copy( results[i].need ),802 copy( results[i].have ), std::move( open ), nextArg + 1,803 expl.cost );804 805 continue;806 }807 808 // add new result809 results.emplace_back(810 i, expl.exprs.front(), std::move( env ), copy( results[i].need ),811 copy( results[i].have ), std::move( open ), nextArg + 1, 0, expl.cost,812 expl.exprs.size() == 1 ? 0 : 1, j );813 }814 }815 816 genStart = genEnd;817 } while( genEnd != results.size() );818 } else {819 // filter out the results that don't use all the arguments820 for ( std::size_t i = genStart; i < results.size(); ++i ) {821 ArgPack & result = results[i];822 if ( ! result.hasExpl() && result.nextArg >= args.size() ) {823 validateFunctionCandidate( func, result, results, out );824 }825 }826 }827 }828 829 /// Adds implicit struct-conversions to the alternative list830 void addAnonConversions( const CandidateRef & cand ) {831 // adds anonymous member interpretations whenever an aggregate value type is seen.832 // it's okay for the aggregate expression to have reference type -- cast it to the833 // base type to treat the aggregate as the referenced value834 ast::ptr< ast::Expr > aggrExpr( cand->expr );835 ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result;836 cand->env.apply( aggrType );837 838 if ( aggrType.as< ast::ReferenceType >() ) {839 aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() };840 }841 842 if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) {843 addAggMembers( structInst, aggrExpr, *cand, Cost::unsafe, "" );844 } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) {845 addAggMembers( unionInst, aggrExpr, *cand, Cost::unsafe, "" );846 }847 }848 849 /// Adds aggregate member interpretations850 void addAggMembers(851 const ast::BaseInstType * aggrInst, const ast::Expr * expr,852 const Candidate & cand, const Cost & addedCost, const std::string & name853 ) {854 for ( const ast::Decl * decl : aggrInst->lookup( name ) ) {855 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl );856 CandidateRef newCand = std::make_shared<Candidate>(857 cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost );858 // add anonymous member interpretations whenever an aggregate value type is seen859 // as a member expression860 addAnonConversions( newCand );861 candidates.emplace_back( std::move( newCand ) );862 }863 }864 865 /// Adds tuple member interpretations866 void addTupleMembers(867 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,868 const Cost & addedCost, const ast::Expr * member869 ) {870 if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) {871 // get the value of the constant expression as an int, must be between 0 and the872 // length of the tuple to have meaning873 long long val = constantExpr->intValue();874 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {875 addCandidate(876 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val },877 addedCost );878 }879 }880 }881 882 void postvisit( const ast::UntypedExpr * untypedExpr ) {883 std::vector< CandidateFinder > argCandidates =884 selfFinder.findSubExprs( untypedExpr->args );885 886 // take care of possible tuple assignments887 // if not tuple assignment, handled as normal function call888 Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates );889 890 CandidateFinder funcFinder( context, tenv );891 if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) {892 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);893 if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) {894 assertf(!argCandidates.empty(), "special function call without argument");895 for (auto & firstArgCand: argCandidates[0]) {896 ast::ptr<ast::Type> argType = firstArgCand->expr->result;897 firstArgCand->env.apply(argType);898 // strip references899 // xxx - is this correct?900 while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base;901 902 // convert 1-tuple to plain type903 if (auto tuple = argType.as<ast::TupleType>()) {904 if (tuple->size() == 1) {905 argType = tuple->types[0];906 }907 }908 909 // if argType is an unbound type parameter, all special functions need to be searched.910 if (isUnboundType(argType)) {911 funcFinder.otypeKeys.clear();912 break;913 }914 915 if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer);916 // else if (const ast::EnumInstType * enumInst = argType.as<ast::EnumInstType>()) {917 // const ast::EnumDecl * enumDecl = enumInst->base; // Here918 // if ( const ast::Type* enumType = enumDecl->base ) {919 // // instance of enum (T) is a instance of type (T)920 // funcFinder.otypeKeys.insert(Mangle::mangle(enumType, Mangle::NoGenericParams | Mangle::Type));921 // } else {922 // // instance of an untyped enum is techically int923 // funcFinder.otypeKeys.insert(Mangle::mangle(enumDecl, Mangle::NoGenericParams | Mangle::Type));924 // }925 // }926 else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type));927 }928 }929 }930 // if candidates are already produced, do not fail931 // xxx - is it possible that handleTupleAssignment and main finder both produce candidates?932 // this means there exists ctor/assign functions with a tuple as first parameter.933 ResolvMode mode = {934 true, // adjust935 !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name936 selfFinder.candidates.empty() // failfast if other options are not found937 };938 funcFinder.find( untypedExpr->func, mode );939 // short-circuit if no candidates940 // if ( funcFinder.candidates.empty() ) return;941 942 reason.code = NoMatch;943 944 // find function operators945 ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" }; // ??? why not ?{}946 CandidateFinder opFinder( context, tenv );947 // okay if there aren't any function operations948 opFinder.find( opExpr, ResolvMode::withoutFailFast() );949 PRINT(950 std::cerr << "known function ops:" << std::endl;951 print( std::cerr, opFinder.candidates, 1 );952 )953 954 // pre-explode arguments955 ExplodedArgs_new argExpansions;956 for ( const CandidateFinder & args : argCandidates ) {957 argExpansions.emplace_back();958 auto & argE = argExpansions.back();959 for ( const CandidateRef & arg : args ) { argE.emplace_back( *arg, symtab ); }960 }961 962 // Find function matches963 CandidateList found;964 SemanticErrorException errors;965 for ( CandidateRef & func : funcFinder ) {966 try {967 PRINT(968 std::cerr << "working on alternative:" << std::endl;969 print( std::cerr, *func, 2 );970 )971 972 // check if the type is a pointer to function973 const ast::Type * funcResult = func->expr->result->stripReferences();974 if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) {975 if ( auto function = pointer->base.as< ast::FunctionType >() ) {976 // if (!selfFinder.allowVoid && function->returns.empty()) continue;977 CandidateRef newFunc{ new Candidate{ *func } };978 newFunc->expr =979 referenceToRvalueConversion( newFunc->expr, newFunc->cost );980 makeFunctionCandidates( newFunc, function, argExpansions, found );981 }982 } else if (983 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )984 ) {985 if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) {986 if ( auto function = clz->bound.as< ast::FunctionType >() ) {987 CandidateRef newFunc{ new Candidate{ *func } };988 newFunc->expr =989 referenceToRvalueConversion( newFunc->expr, newFunc->cost );990 makeFunctionCandidates( newFunc, function, argExpansions, found );991 }992 }993 }994 } catch ( SemanticErrorException & e ) { errors.append( e ); }995 }996 997 // Find matches on function operators `?()`998 if ( ! opFinder.candidates.empty() ) {999 // add exploded function alternatives to front of argument list1000 std::vector< ExplodedArg > funcE;1001 funcE.reserve( funcFinder.candidates.size() );1002 for ( const CandidateRef & func : funcFinder ) {1003 funcE.emplace_back( *func, symtab );1004 }1005 argExpansions.emplace_front( std::move( funcE ) );1006 1007 for ( const CandidateRef & op : opFinder ) {1008 try {1009 // check if type is pointer-to-function1010 const ast::Type * opResult = op->expr->result->stripReferences();1011 if ( auto pointer = dynamic_cast< const ast::PointerType * >( opResult ) ) {1012 if ( auto function = pointer->base.as< ast::FunctionType >() ) {1013 CandidateRef newOp{ new Candidate{ *op} };1014 newOp->expr =1015 referenceToRvalueConversion( newOp->expr, newOp->cost );1016 makeFunctionCandidates( newOp, function, argExpansions, found );1017 }1018 }1019 } catch ( SemanticErrorException & e ) { errors.append( e ); }1020 }1021 }1022 1023 // Implement SFINAE; resolution errors are only errors if there aren't any non-error1024 // candidates1025 if ( found.empty() && ! errors.isEmpty() ) { throw errors; }1026 1027 // only keep the best matching intrinsic result to match C semantics (no unexpected narrowing/widening)1028 // TODO: keep one for each set of argument candidates?1029 Cost intrinsicCost = Cost::infinity;1030 CandidateList intrinsicResult;1031 1032 // Compute conversion costs1033 for ( CandidateRef & withFunc : found ) {1034 Cost cvtCost = computeApplicationConversionCost( withFunc, symtab );1035 1036 PRINT(1037 auto appExpr = withFunc->expr.strict_as< ast::ApplicationExpr >();1038 auto pointer = appExpr->func->result.strict_as< ast::PointerType >();1039 auto function = pointer->base.strict_as< ast::FunctionType >();1040 1041 std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl;1042 std::cerr << "parameters are:" << std::endl;1043 ast::printAll( std::cerr, function->params, 2 );1044 std::cerr << "arguments are:" << std::endl;1045 ast::printAll( std::cerr, appExpr->args, 2 );1046 std::cerr << "bindings are:" << std::endl;1047 ast::print( std::cerr, withFunc->env, 2 );1048 std::cerr << "cost is: " << withFunc->cost << std::endl;1049 std::cerr << "cost of conversion is:" << cvtCost << std::endl;1050 )1051 1052 if ( cvtCost != Cost::infinity ) {1053 withFunc->cvtCost = cvtCost;1054 withFunc->cost += cvtCost;1055 auto func = withFunc->expr.strict_as<ast::ApplicationExpr>()->func.as<ast::VariableExpr>();1056 if (func && func->var->linkage == ast::Linkage::Intrinsic) {1057 if (withFunc->cost < intrinsicCost) {1058 intrinsicResult.clear();1059 intrinsicCost = withFunc->cost;1060 }1061 if (withFunc->cost == intrinsicCost) {1062 intrinsicResult.emplace_back(std::move(withFunc));1063 }1064 }1065 else {1066 candidates.emplace_back( std::move( withFunc ) );1067 }1068 }1069 }1070 spliceBegin( candidates, intrinsicResult );1071 found = std::move( candidates );1072 1073 // use a new list so that candidates are not examined by addAnonConversions twice1074 // CandidateList winners = findMinCost( found );1075 // promoteCvtCost( winners );1076 1077 // function may return a struct/union value, in which case we need to add candidates1078 // for implicit conversions to each of the anonymous members, which must happen after1079 // `findMinCost`, since anon conversions are never the cheapest1080 for ( const CandidateRef & c : found ) {1081 addAnonConversions( c );1082 }1083 // would this be too slow when we don't check cost anymore?1084 spliceBegin( candidates, found );1085 1086 if ( candidates.empty() && targetType && ! targetType->isVoid() && !selfFinder.strictMode ) {1087 // If resolution is unsuccessful with a target type, try again without, since it1088 // will sometimes succeed when it wouldn't with a target type binding.1089 // For example:1090 // forall( otype T ) T & ?[]( T *, ptrdiff_t );1091 // const char * x = "hello world";1092 // unsigned char ch = x[0];1093 // Fails with simple return type binding (xxx -- check this!) as follows:1094 // * T is bound to unsigned char1095 // * (x: const char *) is unified with unsigned char *, which fails1096 // xxx -- fix this better1097 targetType = nullptr;1098 postvisit( untypedExpr );1099 }1100 }1101 1102 /// true if expression is an lvalue1103 static bool isLvalue( const ast::Expr * x ) {1104 return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() );1105 }1106 1107 void postvisit( const ast::AddressExpr * addressExpr ) {1108 CandidateFinder finder( context, tenv );1109 finder.find( addressExpr->arg );1110 1111 if( finder.candidates.empty() ) return;1112 1113 reason.code = NoMatch;1114 1115 for ( CandidateRef & r : finder.candidates ) {1116 if ( ! isLvalue( r->expr ) ) continue;1117 addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } );1118 }1119 }1120 1121 void postvisit( const ast::LabelAddressExpr * labelExpr ) {1122 addCandidate( labelExpr, tenv );1123 }1124 1125 void postvisit( const ast::CastExpr * castExpr ) {1126 ast::ptr< ast::Type > toType = castExpr->result;1127 assert( toType );1128 toType = resolveTypeof( toType, context );1129 toType = adjustExprType( toType, tenv, symtab );1130 1131 CandidateFinder finder( context, tenv, toType );1132 if (toType->isVoid()) {1133 finder.allowVoid = true;1134 }1135 if ( castExpr->kind == ast::CastExpr::Return ) {1136 finder.strictMode = true;1137 finder.find( castExpr->arg, ResolvMode::withAdjustment() );1138 1139 // return casts are eliminated (merely selecting an overload, no actual operation)1140 candidates = std::move(finder.candidates);1141 }1142 finder.find( castExpr->arg, ResolvMode::withAdjustment() );1143 1144 if( !finder.candidates.empty() ) reason.code = NoMatch;1145 1146 CandidateList matches;1147 Cost minExprCost = Cost::infinity;1148 Cost minCastCost = Cost::infinity;1149 for ( CandidateRef & cand : finder.candidates ) {1150 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;1151 ast::OpenVarSet open( cand->open );1152 1153 cand->env.extractOpenVars( open );1154 1155 // It is possible that a cast can throw away some values in a multiply-valued1156 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the1157 // subexpression results that are cast directly. The candidate is invalid if it1158 // has fewer results than there are types to cast to.1159 int discardedValues = cand->expr->result->size() - toType->size();1160 if ( discardedValues < 0 ) continue;1161 1162 // unification run for side-effects1163 unify( toType, cand->expr->result, cand->env, need, have, open );1164 Cost thisCost =1165 (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast)1166 ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env )1167 : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env );1168 1169 PRINT(1170 std::cerr << "working on cast with result: " << toType << std::endl;1171 std::cerr << "and expr type: " << cand->expr->result << std::endl;1172 std::cerr << "env: " << cand->env << std::endl;1173 )1174 if ( thisCost != Cost::infinity ) {1175 PRINT(1176 std::cerr << "has finite cost." << std::endl;1177 )1178 // count one safe conversion for each value that is thrown away1179 thisCost.incSafe( discardedValues );1180 // select first on argument cost, then conversion cost1181 if (cand->cost < minExprCost || cand->cost == minExprCost && thisCost < minCastCost) {1182 minExprCost = cand->cost;1183 minCastCost = thisCost;1184 matches.clear();1185 1186 1187 }1188 // ambiguous case, still output candidates to print in error message1189 if (cand->cost == minExprCost && thisCost == minCastCost) {1190 CandidateRef newCand = std::make_shared<Candidate>(1191 restructureCast( cand->expr, toType, castExpr->isGenerated ),1192 copy( cand->env ), std::move( open ), std::move( need ), cand->cost + thisCost);1193 // currently assertions are always resolved immediately so this should have no effect.1194 // if this somehow changes in the future (e.g. delayed by indeterminate return type)1195 // we may need to revisit the logic.1196 inferParameters( newCand, matches );1197 }1198 // else skip, better alternatives found1199 1200 }1201 }1202 candidates = std::move(matches);1203 1204 //CandidateList minArgCost = findMinCost( matches );1205 //promoteCvtCost( minArgCost );1206 //candidates = findMinCost( minArgCost );1207 }1208 1209 void postvisit( const ast::VirtualCastExpr * castExpr ) {1210 assertf( castExpr->result, "Implicit virtual cast targets not yet supported." );1211 CandidateFinder finder( context, tenv );1212 // don't prune here, all alternatives guaranteed to have same type1213 finder.find( castExpr->arg, ResolvMode::withoutPrune() );1214 for ( CandidateRef & r : finder.candidates ) {1215 addCandidate(1216 *r,1217 new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );1218 }1219 }1220 1221 void postvisit( const ast::KeywordCastExpr * castExpr ) {1222 const auto & loc = castExpr->location;1223 assertf( castExpr->result, "Cast target should have been set in Validate." );1224 auto ref = castExpr->result.strict_as<ast::ReferenceType>();1225 auto inst = ref->base.strict_as<ast::StructInstType>();1226 auto target = inst->base.get();1227 1228 CandidateFinder finder( context, tenv );1229 1230 auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) {1231 for(auto & cand : found) {1232 const ast::Type * expr = cand->expr->result.get();1233 if(expect_ref) {1234 auto res = dynamic_cast<const ast::ReferenceType*>(expr);1235 if(!res) { continue; }1236 expr = res->base.get();1237 }1238 1239 if(auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) {1240 auto td = cand->env.lookup(*insttype);1241 if(!td) { continue; }1242 expr = td->bound.get();1243 }1244 1245 if(auto base = dynamic_cast<const ast::StructInstType*>(expr)) {1246 if(base->base == target) {1247 candidates.push_back( std::move(cand) );1248 reason.code = NoReason;1249 }1250 }1251 }1252 };1253 1254 try {1255 // Attempt 1 : turn (thread&)X into (thread$&)X.__thrd1256 // Clone is purely for memory management1257 std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) };1258 1259 // don't prune here, since it's guaranteed all alternatives will have the same type1260 finder.find( tech1.get(), ResolvMode::withoutPrune() );1261 pick_alternatives(finder.candidates, false);1262 1263 return;1264 } catch(SemanticErrorException & ) {}1265 1266 // Fallback : turn (thread&)X into (thread$&)get_thread(X)1267 std::unique_ptr<const ast::Expr> fallback { ast::UntypedExpr::createDeref(loc, new ast::UntypedExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.getter), { castExpr->arg })) };1268 // don't prune here, since it's guaranteed all alternatives will have the same type1269 finder.find( fallback.get(), ResolvMode::withoutPrune() );1270 1271 pick_alternatives(finder.candidates, true);1272 1273 // Whatever happens here, we have no more fallbacks1274 }1275 1276 void postvisit( const ast::UntypedMemberExpr * memberExpr ) {1277 CandidateFinder aggFinder( context, tenv );1278 aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() );1279 for ( CandidateRef & agg : aggFinder.candidates ) {1280 // it's okay for the aggregate expression to have reference type -- cast it to the1281 // base type to treat the aggregate as the referenced value1282 Cost addedCost = Cost::zero;1283 agg->expr = referenceToRvalueConversion( agg->expr, addedCost );1284 1285 // find member of the given type1286 if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) {1287 addAggMembers(1288 structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );1289 } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) {1290 addAggMembers(1291 unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );1292 } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) {1293 addTupleMembers( tupleType, agg->expr, *agg, addedCost, memberExpr->member );1294 }1295 }1296 }1297 1298 void postvisit( const ast::MemberExpr * memberExpr ) {1299 addCandidate( memberExpr, tenv );1300 }1301 1302 void postvisit( const ast::NameExpr * nameExpr ) {1303 std::vector< ast::SymbolTable::IdData > declList;1304 if (!selfFinder.otypeKeys.empty()) {1305 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);1306 assertf(kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS, "special lookup with non-special target: %s", nameExpr->name.c_str());1307 1308 for (auto & otypeKey: selfFinder.otypeKeys) {1309 auto result = symtab.specialLookupId(kind, otypeKey);1310 declList.insert(declList.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end()));1311 }1312 }1313 else {1314 declList = symtab.lookupId( nameExpr->name );1315 }1316 PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )1317 1318 if( declList.empty() ) return;1319 1320 reason.code = NoMatch;1321 1322 for ( auto & data : declList ) {1323 Cost cost = Cost::zero;1324 ast::Expr * newExpr = data.combine( nameExpr->location, cost );1325 1326 CandidateRef newCand = std::make_shared<Candidate>(1327 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, cost );1328 1329 if (newCand->expr->env) {1330 newCand->env.add(*newCand->expr->env);1331 auto mutExpr = newCand->expr.get_and_mutate();1332 mutExpr->env = nullptr;1333 newCand->expr = mutExpr;1334 }1335 1336 PRINT(1337 std::cerr << "decl is ";1338 ast::print( std::cerr, data.id );1339 std::cerr << std::endl;1340 std::cerr << "newExpr is ";1341 ast::print( std::cerr, newExpr );1342 std::cerr << std::endl;1343 )1344 newCand->expr = ast::mutate_field(1345 newCand->expr.get(), &ast::Expr::result,1346 renameTyVars( newCand->expr->result ) );1347 // add anonymous member interpretations whenever an aggregate value type is seen1348 // as a name expression1349 addAnonConversions( newCand );1350 candidates.emplace_back( std::move( newCand ) );1351 }1352 }1353 1354 void postvisit( const ast::VariableExpr * variableExpr ) {1355 // not sufficient to just pass `variableExpr` here, type might have changed since1356 // creation1357 addCandidate(1358 new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv );1359 }1360 1361 void postvisit( const ast::ConstantExpr * constantExpr ) {1362 addCandidate( constantExpr, tenv );1363 }1364 1365 void postvisit( const ast::SizeofExpr * sizeofExpr ) {1366 if ( sizeofExpr->type ) {1367 addCandidate(1368 new ast::SizeofExpr{1369 sizeofExpr->location, resolveTypeof( sizeofExpr->type, context ) },1370 tenv );1371 } else {1372 // find all candidates for the argument to sizeof1373 CandidateFinder finder( context, tenv );1374 finder.find( sizeofExpr->expr );1375 // find the lowest-cost candidate, otherwise ambiguous1376 CandidateList winners = findMinCost( finder.candidates );1377 if ( winners.size() != 1 ) {1378 SemanticError(1379 sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " );1380 }1381 // return the lowest-cost candidate1382 CandidateRef & choice = winners.front();1383 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );1384 choice->cost = Cost::zero;1385 addCandidate( *choice, new ast::SizeofExpr{ sizeofExpr->location, choice->expr } );1386 }1387 }1388 1389 void postvisit( const ast::AlignofExpr * alignofExpr ) {1390 if ( alignofExpr->type ) {1391 addCandidate(1392 new ast::AlignofExpr{1393 alignofExpr->location, resolveTypeof( alignofExpr->type, context ) },1394 tenv );1395 } else {1396 // find all candidates for the argument to alignof1397 CandidateFinder finder( context, tenv );1398 finder.find( alignofExpr->expr );1399 // find the lowest-cost candidate, otherwise ambiguous1400 CandidateList winners = findMinCost( finder.candidates );1401 if ( winners.size() != 1 ) {1402 SemanticError(1403 alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " );1404 }1405 // return the lowest-cost candidate1406 CandidateRef & choice = winners.front();1407 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );1408 choice->cost = Cost::zero;1409 addCandidate(1410 *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } );1411 }1412 }1413 1414 void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) {1415 const ast::BaseInstType * aggInst;1416 if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ;1417 else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ;1418 else return;1419 1420 for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) {1421 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member );1422 addCandidate(1423 new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv );1424 }1425 }1426 1427 void postvisit( const ast::OffsetofExpr * offsetofExpr ) {1428 addCandidate( offsetofExpr, tenv );1429 }1430 1431 void postvisit( const ast::OffsetPackExpr * offsetPackExpr ) {1432 addCandidate( offsetPackExpr, tenv );1433 }1434 1435 void postvisit( const ast::LogicalExpr * logicalExpr ) {1436 CandidateFinder finder1( context, tenv );1437 finder1.find( logicalExpr->arg1, ResolvMode::withAdjustment() );1438 if ( finder1.candidates.empty() ) return;1439 1440 CandidateFinder finder2( context, tenv );1441 finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() );1442 if ( finder2.candidates.empty() ) return;1443 1444 reason.code = NoMatch;1445 1446 for ( const CandidateRef & r1 : finder1.candidates ) {1447 for ( const CandidateRef & r2 : finder2.candidates ) {1448 ast::TypeEnvironment env{ r1->env };1449 env.simpleCombine( r2->env );1450 ast::OpenVarSet open{ r1->open };1451 mergeOpenVars( open, r2->open );1452 ast::AssertionSet need;1453 mergeAssertionSet( need, r1->need );1454 mergeAssertionSet( need, r2->need );1455 1456 addCandidate(1457 new ast::LogicalExpr{1458 logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd },1459 std::move( env ), std::move( open ), std::move( need ), r1->cost + r2->cost );1460 }1461 }1462 }1463 1464 void postvisit( const ast::ConditionalExpr * conditionalExpr ) {1465 // candidates for condition1466 CandidateFinder finder1( context, tenv );1467 finder1.find( conditionalExpr->arg1, ResolvMode::withAdjustment() );1468 if ( finder1.candidates.empty() ) return;1469 1470 // candidates for true result1471 CandidateFinder finder2( context, tenv );1472 finder2.allowVoid = true;1473 finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() );1474 if ( finder2.candidates.empty() ) return;1475 1476 // candidates for false result1477 CandidateFinder finder3( context, tenv );1478 finder3.allowVoid = true;1479 finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );1480 if ( finder3.candidates.empty() ) return;1481 1482 reason.code = NoMatch;1483 1484 for ( const CandidateRef & r1 : finder1.candidates ) {1485 for ( const CandidateRef & r2 : finder2.candidates ) {1486 for ( const CandidateRef & r3 : finder3.candidates ) {1487 ast::TypeEnvironment env{ r1->env };1488 env.simpleCombine( r2->env );1489 env.simpleCombine( r3->env );1490 ast::OpenVarSet open{ r1->open };1491 mergeOpenVars( open, r2->open );1492 mergeOpenVars( open, r3->open );1493 ast::AssertionSet need;1494 mergeAssertionSet( need, r1->need );1495 mergeAssertionSet( need, r2->need );1496 mergeAssertionSet( need, r3->need );1497 ast::AssertionSet have;1498 1499 // unify true and false results, then infer parameters to produce new1500 // candidates1501 ast::ptr< ast::Type > common;1502 if (1503 unify(1504 r2->expr->result, r3->expr->result, env, need, have, open,1505 common )1506 ) {1507 // generate typed expression1508 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{1509 conditionalExpr->location, r1->expr, r2->expr, r3->expr };1510 newExpr->result = common ? common : r2->expr->result;1511 // convert both options to result type1512 Cost cost = r1->cost + r2->cost + r3->cost;1513 newExpr->arg2 = computeExpressionConversionCost(1514 newExpr->arg2, newExpr->result, symtab, env, cost );1515 newExpr->arg3 = computeExpressionConversionCost(1516 newExpr->arg3, newExpr->result, symtab, env, cost );1517 // output candidate1518 CandidateRef newCand = std::make_shared<Candidate>(1519 newExpr, std::move( env ), std::move( open ), std::move( need ), cost );1520 inferParameters( newCand, candidates );1521 }1522 }1523 }1524 }1525 }1526 1527 void postvisit( const ast::CommaExpr * commaExpr ) {1528 ast::TypeEnvironment env{ tenv };1529 ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, context, env );1530 1531 CandidateFinder finder2( context, env );1532 finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() );1533 1534 for ( const CandidateRef & r2 : finder2.candidates ) {1535 addCandidate( *r2, new ast::CommaExpr{ commaExpr->location, arg1, r2->expr } );1536 }1537 }1538 1539 void postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ) {1540 addCandidate( ctorExpr, tenv );1541 }1542 1543 void postvisit( const ast::ConstructorExpr * ctorExpr ) {1544 CandidateFinder finder( context, tenv );1545 finder.allowVoid = true;1546 finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() );1547 for ( CandidateRef & r : finder.candidates ) {1548 addCandidate( *r, new ast::ConstructorExpr{ ctorExpr->location, r->expr } );1549 }1550 }1551 1552 void postvisit( const ast::RangeExpr * rangeExpr ) {1553 // resolve low and high, accept candidates where low and high types unify1554 CandidateFinder finder1( context, tenv );1555 finder1.find( rangeExpr->low, ResolvMode::withAdjustment() );1556 if ( finder1.candidates.empty() ) return;1557 1558 CandidateFinder finder2( context, tenv );1559 finder2.find( rangeExpr->high, ResolvMode::withAdjustment() );1560 if ( finder2.candidates.empty() ) return;1561 1562 reason.code = NoMatch;1563 1564 for ( const CandidateRef & r1 : finder1.candidates ) {1565 for ( const CandidateRef & r2 : finder2.candidates ) {1566 ast::TypeEnvironment env{ r1->env };1567 env.simpleCombine( r2->env );1568 ast::OpenVarSet open{ r1->open };1569 mergeOpenVars( open, r2->open );1570 ast::AssertionSet need;1571 mergeAssertionSet( need, r1->need );1572 mergeAssertionSet( need, r2->need );1573 ast::AssertionSet have;1574 1575 ast::ptr< ast::Type > common;1576 if (1577 unify(1578 r1->expr->result, r2->expr->result, env, need, have, open,1579 common )1580 ) {1581 // generate new expression1582 ast::RangeExpr * newExpr =1583 new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };1584 newExpr->result = common ? common : r1->expr->result;1585 // add candidate1586 CandidateRef newCand = std::make_shared<Candidate>(1587 newExpr, std::move( env ), std::move( open ), std::move( need ),1588 r1->cost + r2->cost );1589 inferParameters( newCand, candidates );1590 }1591 }1592 }1593 }1594 1595 void postvisit( const ast::UntypedTupleExpr * tupleExpr ) {1596 std::vector< CandidateFinder > subCandidates =1597 selfFinder.findSubExprs( tupleExpr->exprs );1598 std::vector< CandidateList > possibilities;1599 combos( subCandidates.begin(), subCandidates.end(), back_inserter( possibilities ) );1600 1601 for ( const CandidateList & subs : possibilities ) {1602 std::vector< ast::ptr< ast::Expr > > exprs;1603 exprs.reserve( subs.size() );1604 for ( const CandidateRef & sub : subs ) { exprs.emplace_back( sub->expr ); }1605 1606 ast::TypeEnvironment env;1607 ast::OpenVarSet open;1608 ast::AssertionSet need;1609 for ( const CandidateRef & sub : subs ) {1610 env.simpleCombine( sub->env );1611 mergeOpenVars( open, sub->open );1612 mergeAssertionSet( need, sub->need );1613 }1614 1615 addCandidate(1616 new ast::TupleExpr{ tupleExpr->location, std::move( exprs ) },1617 std::move( env ), std::move( open ), std::move( need ), sumCost( subs ) );1618 }1619 }1620 1621 void postvisit( const ast::TupleExpr * tupleExpr ) {1622 addCandidate( tupleExpr, tenv );1623 }1624 1625 void postvisit( const ast::TupleIndexExpr * tupleExpr ) {1626 addCandidate( tupleExpr, tenv );1627 }1628 1629 void postvisit( const ast::TupleAssignExpr * tupleExpr ) {1630 addCandidate( tupleExpr, tenv );1631 }1632 1633 void postvisit( const ast::UniqueExpr * unqExpr ) {1634 CandidateFinder finder( context, tenv );1635 finder.find( unqExpr->expr, ResolvMode::withAdjustment() );1636 for ( CandidateRef & r : finder.candidates ) {1637 // ensure that the the id is passed on so that the expressions are "linked"1638 addCandidate( *r, new ast::UniqueExpr{ unqExpr->location, r->expr, unqExpr->id } );1639 }1640 }1641 1642 void postvisit( const ast::StmtExpr * stmtExpr ) {1643 addCandidate( resolveStmtExpr( stmtExpr, context ), tenv );1644 }1645 1646 void postvisit( const ast::UntypedInitExpr * initExpr ) {1647 // handle each option like a cast1648 CandidateList matches;1649 PRINT(1650 std::cerr << "untyped init expr: " << initExpr << std::endl;1651 )1652 // O(n^2) checks of d-types with e-types1653 for ( const ast::InitAlternative & initAlt : initExpr->initAlts ) {1654 // calculate target type1655 const ast::Type * toType = resolveTypeof( initAlt.type, context );1656 toType = adjustExprType( toType, tenv, symtab );1657 // The call to find must occur inside this loop, otherwise polymorphic return1658 // types are not bound to the initialization type, since return type variables are1659 // only open for the duration of resolving the UntypedExpr.1660 CandidateFinder finder( context, tenv, toType );1661 finder.find( initExpr->expr, ResolvMode::withAdjustment() );1662 1663 Cost minExprCost = Cost::infinity;1664 Cost minCastCost = Cost::infinity;1665 for ( CandidateRef & cand : finder.candidates ) {1666 if(reason.code == NotFound) reason.code = NoMatch;1667 1668 ast::TypeEnvironment env{ cand->env };1669 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;1670 ast::OpenVarSet open{ cand->open };1671 1672 PRINT(1673 std::cerr << " @ " << toType << " " << initAlt.designation << std::endl;1674 )1675 1676 // It is possible that a cast can throw away some values in a multiply-valued1677 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of1678 // the subexpression results that are cast directly. The candidate is invalid1679 // if it has fewer results than there are types to cast to.1680 int discardedValues = cand->expr->result->size() - toType->size();1681 if ( discardedValues < 0 ) continue;1682 1683 // unification run for side-effects1684 bool canUnify = unify( toType, cand->expr->result, env, need, have, open );1685 (void) canUnify;1686 Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(),1687 symtab, env );1688 PRINT(1689 Cost legacyCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(),1690 symtab, env );1691 std::cerr << "Considering initialization:";1692 std::cerr << std::endl << " FROM: " << cand->expr->result << std::endl;1693 std::cerr << std::endl << " TO: " << toType << std::endl;1694 std::cerr << std::endl << " Unification " << (canUnify ? "succeeded" : "failed");1695 std::cerr << std::endl << " Legacy cost " << legacyCost;1696 std::cerr << std::endl << " New cost " << thisCost;1697 std::cerr << std::endl;1698 )1699 if ( thisCost != Cost::infinity ) {1700 // count one safe conversion for each value that is thrown away1701 thisCost.incSafe( discardedValues );1702 if (cand->cost < minExprCost || cand->cost == minExprCost && thisCost < minCastCost) {1703 minExprCost = cand->cost;1704 minCastCost = thisCost;1705 matches.clear();1706 }1707 // ambiguous case, still output candidates to print in error message1708 if (cand->cost == minExprCost && thisCost == minCastCost) {1709 CandidateRef newCand = std::make_shared<Candidate>(1710 new ast::InitExpr{1711 initExpr->location, restructureCast( cand->expr, toType ),1712 initAlt.designation },1713 std::move(env), std::move( open ), std::move( need ), cand->cost + thisCost );1714 // currently assertions are always resolved immediately so this should have no effect.1715 // if this somehow changes in the future (e.g. delayed by indeterminate return type)1716 // we may need to revisit the logic.1717 inferParameters( newCand, matches );1718 }1719 1720 }1721 1722 }1723 1724 }1725 1726 // select first on argument cost, then conversion cost1727 // CandidateList minArgCost = findMinCost( matches );1728 // promoteCvtCost( minArgCost );1729 // candidates = findMinCost( minArgCost );1730 candidates = std::move(matches);1731 }1732 1733 void postvisit( const ast::InitExpr * ) {1734 assertf( false, "CandidateFinder should never see a resolved InitExpr." );1735 }1736 1737 void postvisit( const ast::DeletedExpr * ) {1738 assertf( false, "CandidateFinder should never see a DeletedExpr." );1739 }1740 1741 void postvisit( const ast::GenericExpr * ) {1742 assertf( false, "_Generic is not yet supported." );1743 }1744 };1745 1746 // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder");1747 /// Prunes a list of candidates down to those that have the minimum conversion cost for a given1748 /// return type. Skips ambiguous candidates.1749 1750 } // anonymous namespace1751 1752 bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) {1753 struct PruneStruct {1754 CandidateRef candidate;1755 bool ambiguous;1756 1757 PruneStruct() = default;1758 PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {}1759 };1760 1761 // find lowest-cost candidate for each type1762 std::unordered_map< std::string, PruneStruct > selected;1763 // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found1764 std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;});1765 for ( CandidateRef & candidate : candidates ) {1766 std::string mangleName;1767 {1768 ast::ptr< ast::Type > newType = candidate->expr->result;1769 assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get());1770 candidate->env.apply( newType );1771 mangleName = Mangle::mangle( newType );1772 }1773 1774 auto found = selected.find( mangleName );1775 if (found != selected.end() && found->second.candidate->cost < candidate->cost) {1776 PRINT(1777 std::cerr << "cost " << candidate->cost << " loses to "1778 << found->second.candidate->cost << std::endl;1779 )1780 continue;1781 }1782 1783 // xxx - when do satisfyAssertions produce more than 1 result?1784 // this should only happen when initial result type contains1785 // unbound type parameters, then it should never be pruned by1786 // the previous step, since renameTyVars guarantees the mangled name1787 // is unique.1788 CandidateList satisfied;1789 bool needRecomputeKey = false;1790 if (candidate->need.empty()) {1791 satisfied.emplace_back(candidate);1792 }1793 else {1794 satisfyAssertions(candidate, context.symtab, satisfied, errors);1795 needRecomputeKey = true;1796 }1797 1798 for (auto & newCand : satisfied) {1799 // recomputes type key, if satisfyAssertions changed it1800 if (needRecomputeKey)1801 {1802 ast::ptr< ast::Type > newType = newCand->expr->result;1803 assertf(newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get());1804 newCand->env.apply( newType );1805 mangleName = Mangle::mangle( newType );1806 }1807 auto found = selected.find( mangleName );1808 if ( found != selected.end() ) {1809 // tiebreaking by picking the lower cost on CURRENT expression1810 // NOTE: this behavior is different from C semantics.1811 // Specific remediations are performed for C operators at postvisit(UntypedExpr).1812 // Further investigations may take place.1813 if ( newCand->cost < found->second.candidate->cost1814 || (newCand->cost == found->second.candidate->cost && newCand->cvtCost < found->second.candidate->cvtCost) ) {1815 PRINT(1816 std::cerr << "cost " << newCand->cost << " beats "1817 << found->second.candidate->cost << std::endl;1818 )1819 1820 found->second = PruneStruct{ newCand };1821 } else if ( newCand->cost == found->second.candidate->cost && newCand->cvtCost == found->second.candidate->cvtCost) {1822 // if one of the candidates contains a deleted identifier, can pick the other,1823 // since deleted expressions should not be ambiguous if there is another option1824 // that is at least as good1825 if ( findDeletedExpr( newCand->expr ) ) {1826 // do nothing1827 PRINT( std::cerr << "candidate is deleted" << std::endl; )1828 } else if ( findDeletedExpr( found->second.candidate->expr ) ) {1829 PRINT( std::cerr << "current is deleted" << std::endl; )1830 found->second = PruneStruct{ newCand };1831 } else {1832 PRINT( std::cerr << "marking ambiguous" << std::endl; )1833 found->second.ambiguous = true;1834 }1835 } else {1836 // xxx - can satisfyAssertions increase the cost?1837 PRINT(1838 std::cerr << "cost " << newCand->cost << " loses to "1839 << found->second.candidate->cost << std::endl;1840 )1841 }1842 } else {1843 selected.emplace_hint( found, mangleName, newCand );1844 }1845 }1846 }1847 1848 // report unambiguous min-cost candidates1849 // CandidateList out;1850 for ( auto & target : selected ) {1851 if ( target.second.ambiguous ) continue;1852 1853 CandidateRef cand = target.second.candidate;1854 1855 ast::ptr< ast::Type > newResult = cand->expr->result;1856 cand->env.applyFree( newResult );1857 cand->expr = ast::mutate_field(1858 cand->expr.get(), &ast::Expr::result, std::move( newResult ) );1859 1860 out.emplace_back( cand );1861 }1862 // if everything is lost in satisfyAssertions, report the error1863 return !selected.empty();1864 }1865 1866 void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) {1867 // Find alternatives for expression1868 ast::Pass<Finder> finder{ *this };1869 expr->accept( finder );1870 1871 if ( mode.failFast && candidates.empty() ) {1872 switch(finder.core.reason.code) {1873 case Finder::NotFound:1874 { SemanticError( expr, "No alternatives for expression " ); break; }1875 case Finder::NoMatch:1876 { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; }1877 case Finder::ArgsToFew:1878 case Finder::ArgsToMany:1879 case Finder::RetsToFew:1880 case Finder::RetsToMany:1881 case Finder::NoReason:1882 default:1883 { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); }1884 }1885 }1886 1887 /*1888 if ( mode.satisfyAssns || mode.prune ) {1889 // trim candidates to just those where the assertions are satisfiable1890 // - necessary pre-requisite to pruning1891 CandidateList satisfied;1892 std::vector< std::string > errors;1893 for ( CandidateRef & candidate : candidates ) {1894 satisfyAssertions( candidate, localSyms, satisfied, errors );1895 }1896 1897 // fail early if none such1898 if ( mode.failFast && satisfied.empty() ) {1899 std::ostringstream stream;1900 stream << "No alternatives with satisfiable assertions for " << expr << "\n";1901 for ( const auto& err : errors ) {1902 stream << err;1903 }1904 SemanticError( expr->location, stream.str() );1905 }1906 1907 // reset candidates1908 candidates = move( satisfied );1909 }1910 */1911 1912 // if ( mode.prune ) {1913 // optimization: don't prune for NameExpr since it never has cost1914 if ( mode.prune && !dynamic_cast<const ast::NameExpr *>(expr)) {1915 // trim candidates to single best one1916 PRINT(1917 std::cerr << "alternatives before prune:" << std::endl;1918 print( std::cerr, candidates );1919 )1920 1921 CandidateList pruned;1922 std::vector<std::string> errors;1923 bool found = pruneCandidates( candidates, pruned, errors );1924 1925 if ( mode.failFast && pruned.empty() ) {1926 std::ostringstream stream;1927 if (found) {1928 CandidateList winners = findMinCost( candidates );1929 stream << "Cannot choose between " << winners.size() << " alternatives for "1930 "expression\n";1931 ast::print( stream, expr );1932 stream << " Alternatives are:\n";1933 print( stream, winners, 1 );1934 SemanticError( expr->location, stream.str() );1935 }1936 else {1937 stream << "No alternatives with satisfiable assertions for " << expr << "\n";1938 for ( const auto& err : errors ) {1939 stream << err;1940 }1941 SemanticError( expr->location, stream.str() );1942 }1943 }1944 1945 auto oldsize = candidates.size();1946 candidates = std::move( pruned );1947 1948 PRINT(1949 std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl;1950 )1951 PRINT(1952 std::cerr << "there are " << candidates.size() << " alternatives after elimination"1953 << std::endl;1954 )1955 }1956 1957 // adjust types after pruning so that types substituted by pruneAlternatives are correctly1958 // adjusted1959 if ( mode.adjust ) {1960 for ( CandidateRef & r : candidates ) {1961 r->expr = ast::mutate_field(1962 r->expr.get(), &ast::Expr::result,1963 adjustExprType( r->expr->result, r->env, context.symtab ) );1964 }1965 }1966 1967 // Central location to handle gcc extension keyword, etc. for all expressions1968 for ( CandidateRef & r : candidates ) {1969 if ( r->expr->extension != expr->extension ) {1970 r->expr.get_and_mutate()->extension = expr->extension;1971 }1972 }1973 }1974 1975 std::vector< CandidateFinder > CandidateFinder::findSubExprs(1976 const std::vector< ast::ptr< ast::Expr > > & xs1977 ) {1978 std::vector< CandidateFinder > out;1979 1980 for ( const auto & x : xs ) {1981 out.emplace_back( context, env );1982 out.back().find( x, ResolvMode::withAdjustment() );1983 1984 PRINT(1985 std::cerr << "findSubExprs" << std::endl;1986 print( std::cerr, out.back().candidates );1987 )1988 }1989 1990 return out;1991 }1992 1993 1970 } // namespace ResolvExpr 1994 1971 -
src/ResolvExpr/CandidateFinder.hpp
re172f42 ra0bd9a2 33 33 const ast::TypeEnvironment & env; ///< Substitutions performed in this resolution 34 34 ast::ptr< ast::Type > targetType; ///< Target type for resolution 35 bool strictMode = false; ///< If set to true, requires targetType to be exact match (inside return cast)36 bool allowVoid = false; ///< If set to true, allow void-returning function calls (only top level, cast to void and first in comma)37 35 std::set< std::string > otypeKeys; /// different type may map to same key 38 36 -
src/ResolvExpr/CastCost.cc
re172f42 ra0bd9a2 234 234 if ( typesCompatibleIgnoreQualifiers( src, dst, env ) ) { 235 235 PRINT( std::cerr << "compatible!" << std::endl; ) 236 if (dynamic_cast<const ast::ZeroType *>(dst) || dynamic_cast<const ast::OneType *>(dst)) {237 return Cost::spec;238 }239 236 return Cost::zero; 240 237 } else if ( dynamic_cast< const ast::VoidType * >( dst ) ) { -
src/ResolvExpr/CommonType.cc
re172f42 ra0bd9a2 697 697 if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) { 698 698 #warning remove casts when `commonTypes` moved to new AST 699 700 /*701 699 ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)basic2->kind ]; 702 700 if ( … … 708 706 result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers }; 709 707 } 710 */711 ast::BasicType::Kind kind;712 if (basic->kind != basic2->kind && !widen.first && !widen.second) return;713 else if (!widen.first) kind = basic->kind; // widen.second714 else if (!widen.second) kind = basic2->kind;715 else kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)basic2->kind ];716 // xxx - what does qualifiers even do here??717 if ( (basic->qualifiers >= basic2->qualifiers || widen.first)718 && (basic->qualifiers <= basic2->qualifiers || widen.second) ) {719 result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers };720 }721 722 708 } else if ( 723 709 dynamic_cast< const ast::ZeroType * >( type2 ) … … 726 712 #warning remove casts when `commonTypes` moved to new AST 727 713 ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)ast::BasicType::SignedInt ]; 728 /* 729 if ( // xxx - what does qualifier even do here?? 730 ( ( basic->qualifiers >= type2->qualifiers ) 714 if ( 715 ( ( kind == basic->kind && basic->qualifiers >= type2->qualifiers ) 731 716 || widen.first ) 732 && ( ( /*kind != basic->kind && basic->qualifiers <= type2->qualifiers )717 && ( ( kind != basic->kind && basic->qualifiers <= type2->qualifiers ) 733 718 || widen.second ) 734 ) 735 */ 736 if (widen.second) { 737 result = new ast::BasicType{ basic->kind, basic->qualifiers | type2->qualifiers }; 719 ) { 720 result = new ast::BasicType{ kind, basic->qualifiers | type2->qualifiers }; 738 721 } 739 722 } else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) { … … 763 746 auto entry = open.find( *var ); 764 747 if ( entry != open.end() ) { 765 // if (tenv.lookup(*var)) {766 748 ast::AssertionSet need, have; 767 749 if ( ! tenv.bindVar( -
src/ResolvExpr/ConversionCost.cc
re172f42 ra0bd9a2 702 702 703 703 cost = costCalc( refType->base, dst, srcIsLvalue, symtab, env ); 704 705 // xxx - should qualifiers be considered in pass-by-value?706 /*707 704 if ( refType->base->qualifiers == dst->qualifiers ) { 708 705 cost.incReference(); … … 712 709 cost.incUnsafe(); 713 710 } 714 */715 cost.incReference();716 711 } 717 712 … … 797 792 cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] ); 798 793 } 799 // this has the effect of letting any expr such as x+0, x+1 to be typed800 // the same as x, instead of at least int. are we willing to sacrifice this little801 // bit of coherence with C?802 // TODO: currently this does not work when no zero/one overloads exist. Find a fix for it.803 // cost = Cost::zero;804 794 } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) { 805 795 cost = Cost::zero; 806 796 // +1 for zero_t ->, +1 for disambiguation 807 797 cost.incSafe( maxIntCost + 2 ); 808 // assuming 0p is supposed to be used for pointers?809 798 } 810 799 } … … 815 804 cost = Cost::zero; 816 805 } else if ( const ast::BasicType * dstAsBasic = 817 dynamic_cast< const ast::BasicType * >( dst ) ) { 806 dynamic_cast< const ast::BasicType * >( dst ) ) { 818 807 int tableResult = costMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ]; 819 808 if ( -1 == tableResult ) { … … 824 813 cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] ); 825 814 } 826 827 // cost = Cost::zero;828 815 } 829 816 } -
src/ResolvExpr/FindOpenVars.cc
re172f42 ra0bd9a2 21 21 #include "AST/Pass.hpp" 22 22 #include "AST/Type.hpp" 23 #include "AST/TypeEnvironment.hpp"24 23 #include "Common/PassVisitor.h" 25 24 #include "SynTree/Declaration.h" // for TypeDecl, DeclarationWithType (ptr ... 26 25 #include "SynTree/Type.h" // for Type, Type::ForallList, ArrayType 27 28 #include <iostream>29 26 30 27 namespace ResolvExpr { … … 105 102 ast::AssertionSet & need; 106 103 ast::AssertionSet & have; 107 ast::TypeEnvironment & env;108 104 bool nextIsOpen; 109 105 110 106 FindOpenVars_new( 111 107 ast::OpenVarSet & o, ast::OpenVarSet & c, ast::AssertionSet & n, 112 ast::AssertionSet & h, ast::TypeEnvironment & env,FirstMode firstIsOpen )113 : open( o ), closed( c ), need( n ), have( h ), env (env),nextIsOpen( firstIsOpen ) {}108 ast::AssertionSet & h, FirstMode firstIsOpen ) 109 : open( o ), closed( c ), need( n ), have( h ), nextIsOpen( firstIsOpen ) {} 114 110 115 111 void previsit( const ast::FunctionType * type ) { 116 112 // mark open/closed variables 117 113 if ( nextIsOpen ) { 118 // trying to remove this from resolver.119 // occasionally used in other parts so not deleting right now.120 121 // insert open variables unbound to environment.122 env.add(type->forall);123 124 114 for ( auto & decl : type->forall ) { 125 115 open[ *decl ] = ast::TypeData{ decl->base }; … … 147 137 void findOpenVars( 148 138 const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed, 149 ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env,FirstMode firstIsOpen ) {150 ast::Pass< FindOpenVars_new > finder{ open, closed, need, have, env,firstIsOpen };139 ast::AssertionSet & need, ast::AssertionSet & have, FirstMode firstIsOpen ) { 140 ast::Pass< FindOpenVars_new > finder{ open, closed, need, have, firstIsOpen }; 151 141 type->accept( finder ); 152 153 if (!closed.empty()) {154 std::cerr << "closed: ";155 for (auto& i : closed) {156 std::cerr << i.first.base->location << ":" << i.first.base->name << ' ';157 }158 std::cerr << std::endl;159 }160 142 } 161 143 } // namespace ResolvExpr -
src/ResolvExpr/FindOpenVars.h
re172f42 ra0bd9a2 33 33 void findOpenVars( 34 34 const ast::Type * type, ast::OpenVarSet & open, ast::OpenVarSet & closed, 35 ast::AssertionSet & need, ast::AssertionSet & have, ast::TypeEnvironment & env,FirstMode firstIsOpen );35 ast::AssertionSet & need, ast::AssertionSet & have, FirstMode firstIsOpen ); 36 36 } // namespace ResolvExpr 37 37 -
src/ResolvExpr/Resolver.cc
re172f42 ra0bd9a2 1011 1011 ast::TypeEnvironment env; 1012 1012 CandidateFinder finder( context, env ); 1013 finder.allowVoid = true;1014 1013 finder.find( untyped, recursion_level == 1 ? mode.atTopLevel() : mode ); 1015 1014 --recursion_level; … … 1055 1054 1056 1055 // promote candidate.cvtCost to .cost 1057 //promoteCvtCost( winners );1056 promoteCvtCost( winners ); 1058 1057 1059 1058 // produce ambiguous errors, if applicable -
src/ResolvExpr/SatisfyAssertions.cpp
re172f42 ra0bd9a2 16 16 #include "SatisfyAssertions.hpp" 17 17 18 #include <iostream>19 18 #include <algorithm> 20 19 #include <cassert> … … 46 45 #include "SymTab/Mangler.h" 47 46 48 49 50 47 namespace ResolvExpr { 51 48 … … 68 65 ast::AssertionSet && h, ast::AssertionSet && n, ast::OpenVarSet && o, ast::UniqueId rs ) 69 66 : cdata( c ), adjType( at ), env( std::move( e ) ), have( std::move( h ) ), 70 need( std::move( n ) ), open( std::move( o ) ), resnSlot( rs ) { 71 if (!have.empty()) { 72 std::cerr << c.id->location << ':' << c.id->name << std::endl; 73 } 74 } 67 need( std::move( n ) ), open( std::move( o ) ), resnSlot( rs ) {} 75 68 }; 76 69 … … 146 139 }; 147 140 148 enum AssertionResult {Fail, Skip, Success} ; 141 /// Adds a captured assertion to the symbol table 142 void addToSymbolTable( const ast::AssertionSet & have, ast::SymbolTable & symtab ) { 143 for ( auto & i : have ) { 144 if ( i.second.isUsed ) { symtab.addId( i.first->var ); } 145 } 146 } 149 147 150 148 /// Binds a single assertion, updating satisfaction state … … 157 155 "Assertion candidate does not have a unique ID: %s", toString( candidate ).c_str() ); 158 156 159 ast::Expr * varExpr = match.cdata.combine( cand->expr->location, cand->c ost );157 ast::Expr * varExpr = match.cdata.combine( cand->expr->location, cand->cvtCost ); 160 158 varExpr->result = match.adjType; 161 159 if ( match.resnSlot ) { varExpr->inferred.resnSlots().emplace_back( match.resnSlot ); } … … 167 165 168 166 /// Satisfy a single assertion 169 AssertionResult satisfyAssertion( ast::AssertionList::value_type & assn, SatState & sat, bool skipUnbound = false) {167 bool satisfyAssertion( ast::AssertionList::value_type & assn, SatState & sat, bool allowConversion = false, bool skipUnbound = false) { 170 168 // skip unused assertions 171 static unsigned int cnt = 0; 172 if ( ! assn.second.isUsed ) return AssertionResult::Success; 173 174 if (assn.first->var->name[1] == '|') std::cerr << ++cnt << std::endl; 169 if ( ! assn.second.isUsed ) return true; 175 170 176 171 // find candidates that unify with the desired type 177 AssnCandidateList matches , inexactMatches;172 AssnCandidateList matches; 178 173 179 174 std::vector<ast::SymbolTable::IdData> candidates; … … 184 179 .strict_as<ast::FunctionType>()->params[0] 185 180 .strict_as<ast::ReferenceType>()->base; 186 // sat.cand->env.apply(thisArgType); 187 188 if (auto inst = thisArgType.as<ast::TypeInstType>()) { 189 auto cls = sat.cand->env.lookup(*inst); 190 if (cls && cls->bound) thisArgType = cls->bound; 191 } 181 sat.cand->env.apply(thisArgType); 192 182 193 183 std::string otypeKey = ""; 194 184 if (thisArgType.as<ast::PointerType>()) otypeKey = Mangle::Encoding::pointer; 195 185 else if (!isUnboundType(thisArgType)) otypeKey = Mangle::mangle(thisArgType, Mangle::Type | Mangle::NoGenericParams); 196 else if (skipUnbound) return AssertionResult::Skip;186 else if (skipUnbound) return false; 197 187 198 188 candidates = sat.symtab.specialLookupId(kind, otypeKey); … … 222 212 223 213 ast::OpenVarSet closed; 224 // findOpenVars( toType, newOpen, closed, newNeed, have, FirstClosed ); 225 findOpenVars( adjType, newOpen, closed, newNeed, have, newEnv, FirstOpen ); 226 ast::TypeEnvironment tempNewEnv {newEnv}; 227 228 if ( unifyExact( toType, adjType, tempNewEnv, newNeed, have, newOpen, WidenMode {true, true} ) ) { 229 // set up binding slot for recursive assertions 230 ast::UniqueId crntResnSlot = 0; 231 if ( ! newNeed.empty() ) { 232 crntResnSlot = ++globalResnSlot; 233 for ( auto & a : newNeed ) { a.second.resnSlot = crntResnSlot; } 234 } 235 236 matches.emplace_back( 237 cdata, adjType, std::move( tempNewEnv ), std::move( have ), std::move( newNeed ), 238 std::move( newOpen ), crntResnSlot ); 239 } 240 else if ( matches.empty() ) { 241 // restore invalidated env 242 // newEnv = sat.cand->env; 243 // newNeed.clear(); 214 findOpenVars( toType, newOpen, closed, newNeed, have, FirstClosed ); 215 findOpenVars( adjType, newOpen, closed, newNeed, have, FirstOpen ); 216 if ( allowConversion ) { 244 217 if ( auto c = commonType( toType, adjType, newEnv, newNeed, have, newOpen, WidenMode {true, true} ) ) { 245 218 // set up binding slot for recursive assertions … … 250 223 } 251 224 252 inexactMatches.emplace_back(225 matches.emplace_back( 253 226 cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ), 254 227 std::move( newOpen ), crntResnSlot ); 255 228 } 256 229 } 230 else { 231 if ( unifyExact( toType, adjType, newEnv, newNeed, have, newOpen, WidenMode {true, true} ) ) { 232 // set up binding slot for recursive assertions 233 ast::UniqueId crntResnSlot = 0; 234 if ( ! newNeed.empty() ) { 235 crntResnSlot = ++globalResnSlot; 236 for ( auto & a : newNeed ) { a.second.resnSlot = crntResnSlot; } 237 } 238 239 matches.emplace_back( 240 cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ), 241 std::move( newOpen ), crntResnSlot ); 242 } 243 } 257 244 } 258 245 259 246 // break if no satisfying match 260 if ( matches.empty() ) matches = std::move(inexactMatches); 261 if ( matches.empty() ) return AssertionResult::Fail; 247 if ( matches.empty() ) return false; 262 248 263 249 // defer if too many satisfying matches 264 250 if ( matches.size() > 1 ) { 265 251 sat.deferred.emplace_back( assn.first, assn.second, std::move( matches ) ); 266 return AssertionResult::Success;252 return true; 267 253 } 268 254 269 255 // otherwise bind unique match in ongoing scope 270 256 AssnCandidate & match = matches.front(); 271 //addToSymbolTable( match.have, sat.symtab );257 addToSymbolTable( match.have, sat.symtab ); 272 258 sat.newNeed.insert( match.need.begin(), match.need.end() ); 273 259 sat.cand->env = std::move( match.env ); … … 275 261 276 262 bindAssertion( assn.first, assn.second, sat.cand, match, sat.inferred ); 277 return AssertionResult::Success;263 return true; 278 264 } 279 265 … … 452 438 // for each current mutually-compatible set of assertions 453 439 for ( SatState & sat : sats ) { 440 bool allowConversion = false; 454 441 // stop this branch if a better option is already found 455 442 auto it = thresholds.find( pruneKey( *sat.cand ) ); … … 460 447 for (unsigned resetCount = 0; ; ++resetCount) { 461 448 ast::AssertionList next; 449 resetTyVarRenaming(); 462 450 // make initial pass at matching assertions 463 451 for ( auto & assn : sat.need ) { 464 resetTyVarRenaming();465 452 // fail early if any assertion is not satisfiable 466 auto result = satisfyAssertion( assn, sat, !next.empty() ); 467 if ( result == AssertionResult::Fail ) { 453 if ( ! satisfyAssertion( assn, sat, allowConversion, !next.empty() ) ) { 454 next.emplace_back(assn); 455 // goto nextSat; 456 } 457 } 458 // success 459 if (next.empty()) break; 460 // fail if nothing resolves 461 else if (next.size() == sat.need.size()) { 462 if (allowConversion) { 468 463 Indenter tabs{ 3 }; 469 464 std::ostringstream ss; … … 471 466 print( ss, *sat.cand, ++tabs ); 472 467 ss << (tabs-1) << "Could not satisfy assertion:\n"; 473 ast::print( ss, assn.first, tabs );468 ast::print( ss, next[0].first, tabs ); 474 469 475 470 errors.emplace_back( ss.str() ); 476 471 goto nextSat; 477 472 } 478 else if ( result == AssertionResult::Skip ) { 479 next.emplace_back(assn); 480 // goto nextSat; 481 } 482 } 483 // success 484 if (next.empty()) break; 485 473 474 else { 475 allowConversion = true; 476 continue; 477 } 478 } 479 allowConversion = false; 486 480 sat.need = std::move(next); 487 481 } … … 537 531 sat.cand->expr, std::move( compat.env ), std::move( compat.open ), 538 532 ast::AssertionSet{} /* need moved into satisfaction state */, 539 sat.cand->cost );533 sat.cand->cost, sat.cand->cvtCost ); 540 534 541 535 ast::AssertionSet nextNewNeed{ sat.newNeed }; … … 550 544 for ( DeferRef r : compat.assns ) { 551 545 AssnCandidate match = r.match; 552 //addToSymbolTable( match.have, nextSymtab );546 addToSymbolTable( match.have, nextSymtab ); 553 547 nextNewNeed.insert( match.need.begin(), match.need.end() ); 554 548 -
src/ResolvExpr/Unify.cc
re172f42 ra0bd9a2 160 160 env.apply( newSecond ); 161 161 162 //findOpenVars( newFirst, open, closed, need, have, FirstClosed );163 findOpenVars( newSecond, open, closed, need, have, newEnv,FirstOpen );162 findOpenVars( newFirst, open, closed, need, have, FirstClosed ); 163 findOpenVars( newSecond, open, closed, need, have, FirstOpen ); 164 164 165 165 return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden() ); … … 964 964 // check that the other type is compatible and named the same 965 965 auto otherInst = dynamic_cast< const XInstType * >( other ); 966 if (otherInst && inst->name == otherInst->name) 967 this->result = otherInst; 966 if (otherInst && inst->name == otherInst->name) this->result = otherInst; 968 967 return otherInst; 969 968 } … … 1050 1049 1051 1050 void postvisit( const ast::TypeInstType * typeInst ) { 1052 // assert( open.find( *typeInst ) == open.end() ); 1053 auto otherInst = dynamic_cast< const ast::TypeInstType * >( type2 ); 1054 if (otherInst && typeInst->name == otherInst->name) 1055 this->result = otherInst; 1056 // return otherInst; 1051 assert( open.find( *typeInst ) == open.end() ); 1052 handleRefType( typeInst, type2 ); 1057 1053 } 1058 1054 … … 1165 1161 ) { 1166 1162 ast::OpenVarSet closed; 1167 //findOpenVars( type1, open, closed, need, have, FirstClosed );1168 findOpenVars( type2, open, closed, need, have, env,FirstOpen );1163 findOpenVars( type1, open, closed, need, have, FirstClosed ); 1164 findOpenVars( type2, open, closed, need, have, FirstOpen ); 1169 1165 return unifyInexact( 1170 1166 type1, type2, env, need, have, open, WidenMode{ true, true }, common ); … … 1183 1179 entry1 = var1 ? open.find( *var1 ) : open.end(), 1184 1180 entry2 = var2 ? open.find( *var2 ) : open.end(); 1185 // bool isopen1 = entry1 != open.end(); 1186 // bool isopen2 = entry2 != open.end(); 1187 bool isopen1 = var1 && env.lookup(*var1); 1188 bool isopen2 = var2 && env.lookup(*var2); 1189 1190 /* 1181 bool isopen1 = entry1 != open.end(); 1182 bool isopen2 = entry2 != open.end(); 1183 1191 1184 if ( isopen1 && isopen2 ) { 1192 1185 if ( entry1->second.kind != entry2->second.kind ) return false; … … 1197 1190 return env.bindVar( var1, type2, entry1->second, need, have, open, widen ); 1198 1191 } else if ( isopen2 ) { 1199 return env.bindVar( var2, type1, entry2->second, need, have, open, widen, symtab ); 1200 } */ 1201 if ( isopen1 && isopen2 ) { 1202 if ( var1->base->kind != var2->base->kind ) return false; 1203 return env.bindVarToVar( 1204 var1, var2, ast::TypeData{ var1->base->kind, var1->base->sized||var2->base->sized }, need, have, 1205 open, widen ); 1206 } else if ( isopen1 ) { 1207 return env.bindVar( var1, type2, ast::TypeData{var1->base}, need, have, open, widen ); 1208 } else if ( isopen2 ) { 1209 return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen ); 1210 }else { 1192 return env.bindVar( var2, type1, entry2->second, need, have, open, widen ); 1193 } else { 1211 1194 return ast::Pass<Unify_new>::read( 1212 1195 type1, type2, env, need, have, open, widen ); 1213 1196 } 1214 1215 1197 } 1216 1198 -
src/SynTree/Expression.cc
re172f42 ra0bd9a2 267 267 } 268 268 269 CastExpr::CastExpr( Expression * arg, Type * toType, bool isGenerated , CastKind kind ) : arg(arg), isGenerated( isGenerated ), kind( kind ) {269 CastExpr::CastExpr( Expression * arg, Type * toType, bool isGenerated ) : arg(arg), isGenerated( isGenerated ) { 270 270 set_result(toType); 271 271 } 272 272 273 CastExpr::CastExpr( Expression * arg, bool isGenerated , CastKind kind ) : arg(arg), isGenerated( isGenerated ), kind( kind ) {273 CastExpr::CastExpr( Expression * arg, bool isGenerated ) : arg(arg), isGenerated( isGenerated ) { 274 274 set_result( new VoidType( Type::Qualifiers() ) ); 275 275 } 276 276 277 CastExpr::CastExpr( const CastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), isGenerated( other.isGenerated ) , kind( other.kind ){277 CastExpr::CastExpr( const CastExpr & other ) : Expression( other ), arg( maybeClone( other.arg ) ), isGenerated( other.isGenerated ) { 278 278 } 279 279 -
src/SynTree/Expression.h
re172f42 ra0bd9a2 271 271 bool isGenerated = true; 272 272 273 enum CastKind { 274 Default, // C 275 Coerce, // reinterpret cast 276 Return // overload selection 277 }; 278 279 CastKind kind = Default; 280 281 CastExpr( Expression * arg, bool isGenerated = true, CastKind kind = Default ); 282 CastExpr( Expression * arg, Type * toType, bool isGenerated = true, CastKind kind = Default ); 273 CastExpr( Expression * arg, bool isGenerated = true ); 274 CastExpr( Expression * arg, Type * toType, bool isGenerated = true ); 283 275 CastExpr( Expression * arg, void * ) = delete; // prevent accidentally passing pointers for isGenerated in the first constructor 284 276 CastExpr( const CastExpr & other ); -
src/Tuples/TupleAssignment.cc
re172f42 ra0bd9a2 679 679 680 680 ResolvExpr::CandidateFinder finder( crntFinder.context, matcher->env ); 681 finder.allowVoid = true;682 681 683 682 try { -
src/Validate/Autogen.cpp
re172f42 ra0bd9a2 321 321 void FuncGenerator::produceDecl( const ast::FunctionDecl * decl ) { 322 322 assert( nullptr != decl->stmts ); 323 const auto & oldParams = getGenericParams(type);324 assert( decl->type_params.size() == oldParams.size());325 326 /*327 ast::DeclReplacer::TypeMap typeMap;328 for (auto it = oldParams.begin(), jt = decl->type_params.begin(); it != oldParams.end(); ++it, ++jt) {329 typeMap.emplace(*it, *jt);330 }331 332 const ast::FunctionDecl * mut = strict_dynamic_cast<const ast::FunctionDecl *>(ast::DeclReplacer::replace(decl, typeMap));333 assert (mut == decl);334 */335 323 336 324 definitions.push_back( decl ); … … 364 352 std::vector<ast::ptr<ast::TypeDecl>> type_params; 365 353 std::vector<ast::ptr<ast::DeclWithType>> assertions; 366 367 ast::DeclReplacer::TypeMap typeMap;368 354 for ( auto & old_param : old_type_params ) { 369 355 ast::TypeDecl * decl = ast::deepCopy( old_param ); … … 372 358 oldToNew.emplace( std::make_pair( old_param, decl ) ); 373 359 type_params.push_back( decl ); 374 typeMap.emplace(old_param, decl);375 }376 377 for (auto & param : params) {378 param = ast::DeclReplacer::replace(param, typeMap);379 }380 for (auto & param : returns) {381 param = ast::DeclReplacer::replace(param, typeMap);382 360 } 383 361 replaceAll( params, oldToNew ); … … 544 522 InitTweak::InitExpander_new srcParam( src ); 545 523 // Assign to destination. 546 ast:: MemberExpr * dstSelect = new ast::MemberExpr(524 ast::Expr * dstSelect = new ast::MemberExpr( 547 525 location, 548 526 field, … … 596 574 } 597 575 598 ast:: MemberExpr * srcSelect = (srcParam) ? new ast::MemberExpr(576 ast::Expr * srcSelect = (srcParam) ? new ast::MemberExpr( 599 577 location, field, new ast::VariableExpr( location, srcParam ) 600 578 ) : nullptr; -
tests/collections/vector-demo.cfa
re172f42 ra0bd9a2 143 143 assert( v`capacity > 5 && v`length == 5 ); 144 144 145 v[2] = -0.1 f; // v is [0.0, 98.6, -0.1, 0.2, 0.3]; iter at -0.1, where only the new memory had that change145 v[2] = -0.1; // v is [0.0, 98.6, -0.1, 0.2, 0.3]; iter at -0.1, where only the new memory had that change 146 146 147 147 float val3 = iter`val;
Note:
See TracChangeset
for help on using the changeset viewer.