compiler/resolution/wrappers.cpp
// Add a coercion; replace prevActual and actualSym - the actual to 'call' -
// with the result of the coercion.
Add a coercion; replace prevActual and actualSym - the actual to 'call'
with the result of the coercion.
Add a coercion ; replace prevActual and actualSym - the actual to ' call ' with the result of the coercion .
static void addArgCoercion(FnSymbol*  fn,
                           CallExpr*  call,
                           ArgSymbol* formal,
                           Expr*&     actualExpr,
                           Symbol*&   actualSym,
                           bool&      checkAgain) {
  SET_LINENO(actualExpr);
  Expr*       prevActual = actualExpr;
  Symbol*     prevActualSym = actualSym;
  TypeSymbol* ats        = actualSym->type->symbol;
  TypeSymbol* fts        = formal->type->symbol;
  CallExpr*   castCall   = NULL;
  bool        addedCast  = false;
  VarSymbol*  castTemp   = newTemp("coerce_tmp"); 
  Expr*       newActual  = new SymExpr(castTemp);
  castTemp->addFlag(FLAG_COERCE_TEMP);
  castTemp->addFlag(FLAG_INSERT_AUTO_DESTROY);
  if (actualSym->hasFlag(FLAG_ARG_THIS) &&
      isDispatchParent(actualSym->type, formal->type)) {
    castTemp->addFlag(FLAG_ARG_THIS);
  }
  if (NamedExpr* namedActual = toNamedExpr(prevActual)) {
    Expr* newCurrActual = namedActual->actual;
    newCurrActual->replace(newActual);
    newActual  = prevActual;
    prevActual = newCurrActual;
  } else {
    prevActual->replace(newActual);
  }
  actualExpr = newActual;
  actualSym  = castTemp;
  call->getStmtExpr()->insertBefore(new DefExpr(castTemp));
   We warn addArgCoercion's caller about that via checkAgain:
  if (isSyncType(ats->getValType()) == true) {
    checkAgain = true;
    castCall   = new CallExpr("readFE", gMethodToken, prevActual);
  } else if (isSingleType(ats->getValType()) == true) {
    checkAgain = true;
    castCall   = new CallExpr("readFF", gMethodToken, prevActual);
  } else if (isManagedPtrType(ats->getValType()) == true &&
             !isManagedPtrType(formal->getValType())) {
    checkAgain = true;
    castCall   = new CallExpr("borrow", gMethodToken, prevActual);
  } else if (ats->getValType()->symbol->hasFlag(FLAG_TUPLE) &&
             formal->getValType()->symbol->hasFlag(FLAG_TUPLE) &&
             ats->getValType() != formal->getValType()) {
     Handle tuple cast
    checkAgain = false;
    addedCast = true;
    castTemp->type = formal->getValType();
    castTemp->addFlag(FLAG_EXPR_TEMP);  for lvalue checking
    addTupleCoercion(toAggregateType(ats->getValType()),
                     toAggregateType(formal->getValType()),
                     prevActualSym,
                     castTemp,
                     call->getStmtExpr());
  } else if (ats->getValType()->symbol->hasFlag(FLAG_TUPLE) &&
             formal->getValType()->symbol->hasFlag(FLAG_TUPLE) &&
             fts->hasFlag(FLAG_REF) && !ats->hasFlag(FLAG_REF)) {
     Add a PRIM_ADDR_OF to get the ref to the actual
    castCall = new CallExpr(PRIM_ADDR_OF, prevActual);
    if (prevActualSym->hasFlag(FLAG_EXPR_TEMP))
      castTemp->addFlag(FLAG_EXPR_TEMP);  for lvalue checking
    if (prevActualSym->hasFlag(FLAG_REF_TO_CONST) ||
        prevActualSym->isConstant() ||
        prevActualSym->isParameter()) {
      castTemp->addFlag(FLAG_REF_TO_CONST);
    }
  } else if (ats->hasFlag(FLAG_REF) &&
             !(ats->getValType()->symbol->hasFlag(FLAG_TUPLE) &&
               formal->getValType()->symbol->hasFlag(FLAG_TUPLE)) ) {
     MPF: I'm adding this assert in order to reduce my level
     of concern about this code.
    AggregateType* at = toAggregateType(ats->getValType());
    if (isUserDefinedRecord(at))
      if (propagateNotPOD(at))
        INT_FATAL("would add problematic deref");
     dereference a reference actual
     after dereferencing we may need another coercion, e.g.
       _ref(int)  --coerce->  int  --coerce->  real
     or
       _ref(_syncvar(int)) --> _syncvar(int) --> _ref(int) --> int --> real
    checkAgain = true;
     MPF - this call here is suspect because dereferencing should
     call a record's copy-constructor (e.g. autoCopy).
    castCall   = new CallExpr(PRIM_DEREF, prevActual);
    if (SymExpr* prevSE = toSymExpr(prevActual)) {
      if (prevSE->symbol()->hasFlag(FLAG_REF_TO_CONST)) {
        castTemp->addFlag(FLAG_CONST);
        if (prevSE->symbol()->hasFlag(FLAG_REF_FOR_CONST_FIELD_OF_THIS)) {
          castTemp->addFlag(FLAG_REF_FOR_CONST_FIELD_OF_THIS);
        }
      }
    }
  } else if (isUnmanagedClass(ats->typeInfo()) &&
             isBorrowClass(formal->typeInfo())) {
    checkAgain = true;
    castCall   = new CallExpr(PRIM_CAST, formal->getValType()->symbol, prevActual);
  } else {
     There was code to handle the case when the flag *is* present.
     I deleted that code. The assert ensures it wouldn't apply anyway.
    INT_ASSERT(!actualSym->hasFlag(FLAG_INSTANTIATED_PARAM));
    castCall = NULL;
  }
  if (castCall == NULL && !addedCast) {
     the common case
    castCall = createCast(prevActual, fts);
    if (isString(fts)) {
      castTemp->addFlag(FLAG_INSERT_AUTO_DESTROY);
    }
  }
  if (castCall) {
     move the result to the temp
    CallExpr* castMove = new CallExpr(PRIM_MOVE, castTemp, castCall);
    call->getStmtExpr()->insertBefore(castMove);
    resolveCallAndCallee(castCall, true);
    if (FnSymbol* castTarget = castCall->resolvedFunction()) {
       Perhaps equivalently, we could check "if (tryToken)",
       except tryToken is not visible in this file.
      if (!castTarget->hasFlag(FLAG_RESOLVED)) {
         This happens e.g. when castTarget itself has an error.
         Todo: in this case, we should report the error at the point
         where it arises, supposedly within resolveFns(castTarget).
         Why is it not reported there?
        USR_FATAL_CONT(call,
                       "Error resolving a cast from %s to %s",
                       ats->name,
                       fts->name);
        USR_PRINT(castTarget, "  the troublesome function is here");
        USR_STOP();
      }
    }
    resolveCall(castMove);
  }
   Check for coercions resulting in a value that
   they are not passed by ref or const ref.
  if (!castTemp->isRef()) {
    errorIfValueCoercionToRef(call, formal);
  }
}
static void addArgCoercion ( FnSymbol * fn , CallExpr * call , ArgSymbol * formal , Expr * & actualExpr , Symbol * & actualSym , bool & checkAgain ) { SET_LINENO ( actualExpr ) ; Expr * prevActual = actualExpr ; Symbol * prevActualSym = actualSym ; TypeSymbol * ats = actualSym -> type -> symbol ; TypeSymbol * fts = formal -> type -> symbol ; CallExpr * castCall = NULL ; bool addedCast = false ; VarSymbol * castTemp = newTemp ( " " ) ; Expr * newActual = new SymExpr ( castTemp ) ; castTemp -> addFlag ( FLAG_COERCE_TEMP ) ; castTemp -> addFlag ( FLAG_INSERT_AUTO_DESTROY ) ; if ( actualSym -> hasFlag ( FLAG_ARG_THIS ) && isDispatchParent ( actualSym -> type , formal -> type ) ) { castTemp -> addFlag ( FLAG_ARG_THIS ) ; } if ( NamedExpr * namedActual = toNamedExpr ( prevActual ) ) { Expr * newCurrActual = namedActual -> actual ; newCurrActual -> replace ( newActual ) ; newActual = prevActual ; prevActual = newCurrActual ; } else { prevActual -> replace ( newActual ) ; } actualExpr = newActual ; actualSym = castTemp ; call -> getStmtExpr ( ) -> insertBefore ( new DefExpr ( castTemp ) ) ; if ( isSyncType ( ats -> getValType ( ) ) == true ) { checkAgain = true ; castCall = new CallExpr ( " " , gMethodToken , prevActual ) ; } else if ( isSingleType ( ats -> getValType ( ) ) == true ) { checkAgain = true ; castCall = new CallExpr ( " " , gMethodToken , prevActual ) ; } else if ( isManagedPtrType ( ats -> getValType ( ) ) == true && ! isManagedPtrType ( formal -> getValType ( ) ) ) { checkAgain = true ; castCall = new CallExpr ( " " , gMethodToken , prevActual ) ; } else if ( ats -> getValType ( ) -> symbol -> hasFlag ( FLAG_TUPLE ) && formal -> getValType ( ) -> symbol -> hasFlag ( FLAG_TUPLE ) && ats -> getValType ( ) != formal -> getValType ( ) ) { checkAgain = false ; addedCast = true ; castTemp -> type = formal -> getValType ( ) ; castTemp -> addFlag ( FLAG_EXPR_TEMP ) ; addTupleCoercion ( toAggregateType ( ats -> getValType ( ) ) , toAggregateType ( formal -> getValType ( ) ) , prevActualSym , castTemp , call -> getStmtExpr ( ) ) ; } else if ( ats -> getValType ( ) -> symbol -> hasFlag ( FLAG_TUPLE ) && formal -> getValType ( ) -> symbol -> hasFlag ( FLAG_TUPLE ) && fts -> hasFlag ( FLAG_REF ) && ! ats -> hasFlag ( FLAG_REF ) ) { castCall = new CallExpr ( PRIM_ADDR_OF , prevActual ) ; if ( prevActualSym -> hasFlag ( FLAG_EXPR_TEMP ) ) castTemp -> addFlag ( FLAG_EXPR_TEMP ) ; if ( prevActualSym -> hasFlag ( FLAG_REF_TO_CONST ) || prevActualSym -> isConstant ( ) || prevActualSym -> isParameter ( ) ) { castTemp -> addFlag ( FLAG_REF_TO_CONST ) ; } } else if ( ats -> hasFlag ( FLAG_REF ) && ! ( ats -> getValType ( ) -> symbol -> hasFlag ( FLAG_TUPLE ) && formal -> getValType ( ) -> symbol -> hasFlag ( FLAG_TUPLE ) ) ) { AggregateType * at = toAggregateType ( ats -> getValType ( ) ) ; if ( isUserDefinedRecord ( at ) ) if ( propagateNotPOD ( at ) ) INT_FATAL ( " " ) ; checkAgain = true ; castCall = new CallExpr ( PRIM_DEREF , prevActual ) ; if ( SymExpr * prevSE = toSymExpr ( prevActual ) ) { if ( prevSE -> symbol ( ) -> hasFlag ( FLAG_REF_TO_CONST ) ) { castTemp -> addFlag ( FLAG_CONST ) ; if ( prevSE -> symbol ( ) -> hasFlag ( FLAG_REF_FOR_CONST_FIELD_OF_THIS ) ) { castTemp -> addFlag ( FLAG_REF_FOR_CONST_FIELD_OF_THIS ) ; } } } } else if ( isUnmanagedClass ( ats -> typeInfo ( ) ) && isBorrowClass ( formal -> typeInfo ( ) ) ) { checkAgain = true ; castCall = new CallExpr ( PRIM_CAST , formal -> getValType ( ) -> symbol , prevActual ) ; } else { INT_ASSERT ( ! actualSym -> hasFlag ( FLAG_INSTANTIATED_PARAM ) ) ; castCall = NULL ; } if ( castCall == NULL && ! addedCast ) { castCall = createCast ( prevActual , fts ) ; if ( isString ( fts ) ) { castTemp -> addFlag ( FLAG_INSERT_AUTO_DESTROY ) ; } } if ( castCall ) { CallExpr * castMove = new CallExpr ( PRIM_MOVE , castTemp , castCall ) ; call -> getStmtExpr ( ) -> insertBefore ( castMove ) ; resolveCallAndCallee ( castCall , true ) ; if ( FnSymbol * castTarget = castCall -> resolvedFunction ( ) ) { if ( ! castTarget -> hasFlag ( FLAG_RESOLVED ) ) { USR_FATAL_CONT ( call , " " , ats -> name , fts -> name ) ; USR_PRINT ( castTarget , " " ) ; USR_STOP ( ) ; } } resolveCall ( castMove ) ; } if ( ! castTemp -> isRef ( ) ) { errorIfValueCoercionToRef ( call , formal ) ; } }
Add a coercion; replace prevActual and actualSym - the actual to 'call'
with the result of the coercion.
Add a coercion ; replace prevActual and actualSym - the actual to ' call ' with the result of the coercion .
// ..., formal->type ? // preserve the named portion // Now 'prevActual' has been removed+replaced and is ready to be passed // as an actual to a cast or some such. // We can update addArgCoercion's caller right away. // Add the Def for castTemp // Here we will often strip the type of its sync-ness. // After that we may need another coercion(s), e.g. //   _syncvar(int) --readFE()-> int -> real // // We warn addArgCoercion's caller about that via checkAgain: // Handle tuple cast // for lvalue checking // Add a PRIM_ADDR_OF to get the ref to the actual // for lvalue checking // MPF: I'm adding this assert in order to reduce my level // of concern about this code. // // dereference a reference actual // // after dereferencing we may need another coercion, e.g. //   _ref(int)  --coerce->  int  --coerce->  real // or //   _ref(_syncvar(int)) --> _syncvar(int) --> _ref(int) --> int --> real // // MPF - this call here is suspect because dereferencing should // call a record's copy-constructor (e.g. autoCopy). // There was code to handle the case when the flag *is* present. // I deleted that code. The assert ensures it wouldn't apply anyway. // the common case // move the result to the temp // Perhaps equivalently, we could check "if (tryToken)", // except tryToken is not visible in this file. // This happens e.g. when castTarget itself has an error. // Todo: in this case, we should report the error at the point // where it arises, supposedly within resolveFns(castTarget). // Why is it not reported there? // Check for coercions resulting in a value that // they are not passed by ref or const ref.