compiler/resolution/functionResolution.cpp
/************************************* | **************************************
*                                                                             *
* Handles the initialization of fields in default initializers when the type  *
* was not known at the generation of the default initializer and the field    *
* no declared initial value.                                                  *
*                                                                             *
* If the field's type is now determined to be a sync or single, then we will  *
* transform this call into just a PRIM_SET_MEMBER and resolve that.           *
*                                                                             *
* If this is not the case, then we will expand the call into the normal field *
* initialization.                                                             *
*
* The concern for default initializers with sync fields is
* that the compiler will generate this pattern:
*
*   - create a default-initialized (empty) sync value
*   - call = to initialize the field from it
*   -> deadlock because the RHS of = is empty
*
* TODO: revisit and decide if PRIM_INIT_MAYBE_SYNC_SINGLE_FIELD
* is still necessary, now that default initializers should not
* call = (and instead use in intent at the call site).
*
************************************** | *************************************/
|
Handles the initialization of fields in default initializers when the type
was not known at the generation of the default initializer and the field
no declared initial value.

If the field's type is now determined to be a sync or single, then we will
transform this call into just a PRIM_SET_MEMBER and resolve that.

If this is not the case, then we will expand the call into the normal field
initialization.

The concern for default initializers with sync fields is
that the compiler will generate this pattern.

create a default-initialized (empty) sync value
call = to initialize the field from it
> deadlock because the RHS of = is empty

revisit and decide if PRIM_INIT_MAYBE_SYNC_SINGLE_FIELD
is still necessary, now that default initializers should not
call = (and instead use in intent at the call site).


| Handles the initialization of fields in default initializers when the type was not known at the generation of the default initializer and the field no declared initial value . If the field ' s type is now determined to be a sync or single then we will transform this call into just a PRIM_SET_MEMBER and resolve that . If this is not the case then we will expand the call into the normal field initialization . The concern for default initializers with sync fields is that the compiler will generate this pattern . create a default - initialized ( empty ) sync value call = to initialize the field from it > deadlock because the RHS of = is empty revisit and decide if PRIM_INIT_MAYBE_SYNC_SINGLE_FIELD is still necessary now that default initializers should not call = ( and instead use in intent at the call site ) .
static void resolveMaybeSyncSingleField(CallExpr* call) {
  if (call->id == breakOnResolveID) {
    gdbShouldBreakHere();
  }
  INT_ASSERT(call->argList.length == 3);
  SymExpr* rhs = toSymExpr(call->get(3)); 
  SymExpr* sym = toSymExpr(call->get(2));
  if (!sym)
    INT_FATAL(call, "bad initializer set field primitive");
  VarSymbol* var = toVarSymbol(sym->symbol());
  if (!var || !var->immediate)
    INT_FATAL(call, "bad initializer set field primitive");
  const char* name = var->immediate->v_string;
  AggregateType* ct = toAggregateType(call->get(1)->typeInfo()->getValType());
  if (!ct)
    INT_FATAL(call, "bad initializer set field primitive");
  Symbol* fs = NULL;
  int index = 1;
  for_fields(field, ct) {
    if (!strcmp(field->name, name)) {
      fs = field; break;
    }
    index++;
  }
  if (!fs)
    INT_FATAL(call, "bad initializer set field primitive");
  Type* t = rhs->typeInfo();
  if (t == dtUnknown)
    INT_FATAL(call, "Unable to resolve field type");
  if (isSyncType(t) || isSingleType(t)) {
    call->primitive = primitives[PRIM_SET_MEMBER];
    resolveSetMember(call);
  } else {
    DefExpr*   fieldDef  = fs->defPoint;
    VarSymbol* tmp       = newTemp("tmp", t->getValType());
    DefExpr*   tmpDefn   = new DefExpr(tmp);
    CallExpr*  tmpInit   = new CallExpr(PRIM_INIT_VAR,
                                        tmp, rhs->remove(),
                                        fieldDef->exprType->copy());
    call->primitive = primitives[PRIM_SET_MEMBER];
    call->insertAtTail(new SymExpr(tmp));
    FnSymbol*      parentFn = toFnSymbol(call->parentSymbol);
    INT_ASSERT(parentFn);
    Symbol*        _this    = parentFn->_this;
    AggregateType* at       = toAggregateType(_this->type);
    INT_ASSERT(at);
    BlockStmt* resolveBlock = new BlockStmt(tmpDefn, BLOCK_SCOPELESS);
    resolveBlock->insertAtTail(tmpInit);
    call->replace(resolveBlock);
    resolveBlock->insertAtTail(call);
    if (!isFieldAccessible(tmpInit, at, fieldDef)) {
      INT_ASSERT(false);
    }
    updateFieldsMember(tmpInit, parentFn, fieldDef);
    normalize(resolveBlock);
    resolveBlockStmt(resolveBlock);
  }
}
static void resolveMaybeSyncSingleField ( CallExpr * call ) { if ( call -> id == breakOnResolveID ) { gdbShouldBreakHere ( ) ; } INT_ASSERT ( call -> argList . length == 3 ) ; SymExpr * rhs = toSymExpr ( call -> get ( 3 ) ) ; SymExpr * sym = toSymExpr ( call -> get ( 2 ) ) ; if ( ! sym ) INT_FATAL ( call , " " ) ; VarSymbol * var = toVarSymbol ( sym -> symbol ( ) ) ; if ( ! var || ! var -> immediate ) INT_FATAL ( call , " " ) ; const char * name = var -> immediate -> v_string ; AggregateType * ct = toAggregateType ( call -> get ( 1 ) -> typeInfo ( ) -> getValType ( ) ) ; if ( ! ct ) INT_FATAL ( call , " " ) ; Symbol * fs = NULL ; int index = 1 ; for_fields ( field , ct ) { if ( ! strcmp ( field -> name , name ) ) { fs = field ; break ; } index ++ ; } if ( ! fs ) INT_FATAL ( call , " " ) ; Type * t = rhs -> typeInfo ( ) ; if ( t == dtUnknown ) INT_FATAL ( call , " " ) ; if ( isSyncType ( t ) || isSingleType ( t ) ) { call -> primitive = primitives [ PRIM_SET_MEMBER ] ; resolveSetMember ( call ) ; } else { DefExpr * fieldDef = fs -> defPoint ; VarSymbol * tmp = newTemp ( " " , t -> getValType ( ) ) ; DefExpr * tmpDefn = new DefExpr ( tmp ) ; CallExpr * tmpInit = new CallExpr ( PRIM_INIT_VAR , tmp , rhs -> remove ( ) , fieldDef -> exprType -> copy ( ) ) ; call -> primitive = primitives [ PRIM_SET_MEMBER ] ; call -> insertAtTail ( new SymExpr ( tmp ) ) ; FnSymbol * parentFn = toFnSymbol ( call -> parentSymbol ) ; INT_ASSERT ( parentFn ) ; Symbol * _this = parentFn -> _this ; AggregateType * at = toAggregateType ( _this -> type ) ; INT_ASSERT ( at ) ; BlockStmt * resolveBlock = new BlockStmt ( tmpDefn , BLOCK_SCOPELESS ) ; resolveBlock -> insertAtTail ( tmpInit ) ; call -> replace ( resolveBlock ) ; resolveBlock -> insertAtTail ( call ) ; if ( ! isFieldAccessible ( tmpInit , at , fieldDef ) ) { INT_ASSERT ( false ) ; } updateFieldsMember ( tmpInit , parentFn , fieldDef ) ; normalize ( resolveBlock ) ; resolveBlockStmt ( resolveBlock ) ; } }
|
Handles the initialization of fields in default initializers when the type
was not known at the generation of the default initializer and the field
no declared initial value.
| Handles the initialization of fields in default initializers when the type was not known at the generation of the default initializer and the field no declared initial value .
// PRIM_INIT_MAYBE_SYNC_SINGLE_FIELD contains three args: // fn->_this, the name of the field, and the value it is to be given // the value/type to give the field // Get the field name. // Get the type // I think this never happens, so can be turned into an assert // Note: intentionally skips this branch for refs to sync vars // Sync and single fields should be initialized with just a PRIM_SET_MEMBER // using the original initial expression. // Create the precursor code that would have been inserted if we weren't so // worried about syncs and singles // Applies a type to TMP and sets its value // Needed bits for the next few calls