compiler/resolution/functionResolution.cpp
// Returns a relevant FnSymbol if it worked
Returns a relevant FnSymbol if it worked
Returns a relevant FnSymbol if it worked
static FnSymbol* resolveForwardedCall(CallInfo& info, bool checkOnly) {
  CallExpr* call = info.call;
  const char* calledName = info.name;
  const char* inFnName = call->getFunction()->name;
  Expr* receiver = call->get(2);
  Type* t = receiver->getValType();
  AggregateType* at = toAggregateType(canonicalClassType(t));
  FnSymbol* bestFn = NULL;
  CallExpr* bestCall = NULL;
  BlockStmt* bestBlock = NULL;
  ForwardingStmt* bestDelegate = NULL;
  const char* ignorePrefix = "chpl_forwarding_expr";
  if (0 == memcmp(ignorePrefix, calledName, strlen(ignorePrefix)))
    return NULL;
  if (0 == strcmp(calledName, "chpl__promotionType"))
    return NULL;
  detectForwardingCycle(call);
  for_alist(expr, at->forwardingTo) {
    ForwardingStmt* delegate = toForwardingStmt(expr);
    INT_ASSERT(delegate);
    SET_LINENO(delegate);
    if (inFnName == delegate->fnReturningForwarding)
      continue;
    const char* methodName = NULL;
    methodName = getForwardedMethodName(calledName, delegate);
    if (methodName == NULL) {
      continue;
    }
    CallExpr* forwardedCall = call->copy();
    BlockStmt* block = new BlockStmt(forwardedCall, BLOCK_SCOPELESS);
    call->getStmtExpr()->insertBefore(block);
    FnSymbol* fn = NULL;
    fn = adjustAndResolveForwardedCall(forwardedCall, delegate, methodName);
    if (fn) {
      if (bestFn == NULL) {
        bestFn = fn;
        bestCall = forwardedCall;
        bestBlock = block;
        bestDelegate = delegate;
      } else {
        USR_FATAL_CONT(call, "ambiguous forwarded call");
        USR_PRINT(bestFn, "candidates include: %s", toString(bestFn));
        USR_PRINT(bestDelegate, "from forwarding statement here");
        USR_PRINT(fn, "candidates include: %s", toString(fn));
        USR_PRINT(delegate, "from forwarding statement here");
        USR_STOP();
      }
    } else {
      block->remove();
    }
  }
  if (bestFn != NULL) {
    if (isContextCallExpr(bestCall->parentExpr)) {
      bestBlock->remove();
      const char* methodName = getForwardedMethodName(calledName, bestDelegate);
      INT_ASSERT(methodName);
      bestFn = adjustAndResolveForwardedCall(call, bestDelegate, methodName);
    } else {
      for_actuals(actual, call) {
        actual->remove();
      }
      call->baseExpr->replace(bestCall->baseExpr->remove());
      call->partialTag = bestCall->partialTag;
      for_actuals(actual, bestCall) {
        call->insertAtTail(actual->remove());
      }
      bestCall->remove();
      bestBlock->flattenAndRemove();
    }
  }
  return bestFn;
}
static FnSymbol * resolveForwardedCall ( CallInfo & info , bool checkOnly ) { CallExpr * call = info . call ; const char * calledName = info . name ; const char * inFnName = call -> getFunction ( ) -> name ; Expr * receiver = call -> get ( 2 ) ; Type * t = receiver -> getValType ( ) ; AggregateType * at = toAggregateType ( canonicalClassType ( t ) ) ; FnSymbol * bestFn = NULL ; CallExpr * bestCall = NULL ; BlockStmt * bestBlock = NULL ; ForwardingStmt * bestDelegate = NULL ; const char * ignorePrefix = " " ; if ( 0 == memcmp ( ignorePrefix , calledName , strlen ( ignorePrefix ) ) ) return NULL ; if ( 0 == strcmp ( calledName , " " ) ) return NULL ; detectForwardingCycle ( call ) ; for_alist ( expr , at -> forwardingTo ) { ForwardingStmt * delegate = toForwardingStmt ( expr ) ; INT_ASSERT ( delegate ) ; SET_LINENO ( delegate ) ; if ( inFnName == delegate -> fnReturningForwarding ) continue ; const char * methodName = NULL ; methodName = getForwardedMethodName ( calledName , delegate ) ; if ( methodName == NULL ) { continue ; } CallExpr * forwardedCall = call -> copy ( ) ; BlockStmt * block = new BlockStmt ( forwardedCall , BLOCK_SCOPELESS ) ; call -> getStmtExpr ( ) -> insertBefore ( block ) ; FnSymbol * fn = NULL ; fn = adjustAndResolveForwardedCall ( forwardedCall , delegate , methodName ) ; if ( fn ) { if ( bestFn == NULL ) { bestFn = fn ; bestCall = forwardedCall ; bestBlock = block ; bestDelegate = delegate ; } else { USR_FATAL_CONT ( call , " " ) ; USR_PRINT ( bestFn , " " , toString ( bestFn ) ) ; USR_PRINT ( bestDelegate , " " ) ; USR_PRINT ( fn , " " , toString ( fn ) ) ; USR_PRINT ( delegate , " " ) ; USR_STOP ( ) ; } } else { block -> remove ( ) ; } } if ( bestFn != NULL ) { if ( isContextCallExpr ( bestCall -> parentExpr ) ) { bestBlock -> remove ( ) ; const char * methodName = getForwardedMethodName ( calledName , bestDelegate ) ; INT_ASSERT ( methodName ) ; bestFn = adjustAndResolveForwardedCall ( call , bestDelegate , methodName ) ; } else { for_actuals ( actual , call ) { actual -> remove ( ) ; } call -> baseExpr -> replace ( bestCall -> baseExpr -> remove ( ) ) ; call -> partialTag = bestCall -> partialTag ; for_actuals ( actual , bestCall ) { call -> insertAtTail ( actual -> remove ( ) ) ; } bestCall -> remove ( ) ; bestBlock -> flattenAndRemove ( ) ; } } return bestFn ; }
Returns a relevant FnSymbol if it worked
Returns a relevant FnSymbol if it worked
// Don't forward forwarding expr (infinite loop ensues) // This is a workaround for resolvePromotionType being called // when some fields have unknown type. A better solution // is preferred. // Detect cycles // Try each of the forwarding clauses to see if any get us // a match. // Forwarding method should use line number of forwarding stmt // Don't try to recursively forward when processing // forwarding expression! // Adjust methodName for rename processing. // Stop processing this delegate if we've ruled out this name. // Create a block to store temporaries etc. // Store it just before the call being resolved. // Remove the block for any forwards that didn't resolve // Replace call with bestCall and put any statements in bestBlock // just before the call, then remove bestBlock. // retry to get the right ContextCall expression // Adjust methodName for rename processing. // Replace actuals in call with those from bestCall // Note that the above path could be used instead, but // this branch hopefully makes fewer temporary AST nodes.