TypeSpec ASTfunction_call::typecheck_all_poly (TypeSpec expected, bool coerce) { for (FunctionSymbol *poly = func(); poly; poly = poly->nextpoly()) { const char *code = poly->argcodes().c_str(); int advance; TypeSpec returntype = m_compiler->type_from_code (code, &advance); code += advance; if (check_arglist (m_name.c_str(), args(), code, coerce)) { // Return types also must match if not coercible if (coerce || expected == TypeSpec() || expected == returntype) { m_sym = poly; return returntype; } } } return TypeSpec(); }
void OSLCompilerImpl::initialize_builtin_funcs () { for (int i = 0; builtin_func_args[i]; ++i) { ustring funcname (builtin_func_args[i++]); // Count the number of polymorphic versions and look for any // special hint markers. int npoly = 0; bool readwrite_special_case = false; bool texture_args = false; bool printf_args = false; bool takes_derivs = false; for (npoly = 0; builtin_func_args[i+npoly]; ++npoly) { if (! strcmp (builtin_func_args[i+npoly], "!rw")) readwrite_special_case = true; else if (! strcmp (builtin_func_args[i+npoly], "!tex")) texture_args = true; else if (! strcmp (builtin_func_args[i+npoly], "!printf")) printf_args = true; else if (! strcmp (builtin_func_args[i+npoly], "!deriv")) takes_derivs = true; } // Now add them in reverse order, so the order in the table is // the priority order for approximate matches. for (int j = npoly-1; j >= 0; --j) { if (builtin_func_args[i+j][0] == '!') // Skip special hints continue; ustring poly (builtin_func_args[i+j]); Symbol *last = symtab().clash (funcname); ASSERT (last == NULL || last->symtype() == SymTypeFunction); TypeSpec rettype = type_from_code (poly.c_str()); FunctionSymbol *f = new FunctionSymbol (funcname, rettype); f->nextpoly ((FunctionSymbol *)last); f->argcodes (poly); f->readwrite_special_case (readwrite_special_case); f->texture_args (texture_args); f->printf_args (printf_args); f->takes_derivs (takes_derivs); symtab().insert (f); } i += npoly; } }
TypeSpec ASTfunction_call::typecheck (TypeSpec expected) { typecheck_children (); bool match = false; // Look for an exact match, including expected return type m_typespec = typecheck_all_poly (expected, false); if (m_typespec != TypeSpec()) match = true; // Now look for an exact match on args, but any assignable return type if (! match && expected != TypeSpec()) { m_typespec = typecheck_all_poly (TypeSpec(), false); if (m_typespec != TypeSpec()) match = true; } // Now look for a coercible match of args, exact march on return type if (! match) { m_typespec = typecheck_all_poly (expected, true); if (m_typespec != TypeSpec()) match = true; } // All that failed, try for a coercible match on everything if (! match && expected != TypeSpec()) { m_typespec = typecheck_all_poly (TypeSpec(), true); if (m_typespec != TypeSpec()) match = true; } if (match) { if (! is_user_function ()) typecheck_builtin_specialcase (); return m_typespec; } // Couldn't find any way to match any polymorphic version of the // function that we know about. OK, at least try for helpful error // message. std::string choices (""); for (FunctionSymbol *poly = func(); poly; poly = poly->nextpoly()) { const char *code = poly->argcodes().c_str(); int advance; TypeSpec returntype = m_compiler->type_from_code (code, &advance); code += advance; if (choices.length()) choices += "\n"; choices += Strutil::format ("\t%s %s (%s)", type_c_str(returntype), m_name.c_str(), m_compiler->typelist_from_code(code).c_str()); } std::string actualargs; for (ASTNode::ref arg = args(); arg; arg = arg->next()) { if (actualargs.length()) actualargs += ", "; actualargs += arg->typespec().string(); } error ("No matching function call to '%s (%s)'\n Candidates are:\n%s", m_name.c_str(), actualargs.c_str(), choices.c_str()); return TypeSpec(); }