compiler/passes/normalize.cpp
// call - the type constructor or build tuple call currently being considered
// queryToCopy - a PRIM_QUERY formal, ... recording the path to the current call
the type constructor or build tuple call currently being considered
queryToCopy - a PRIM_QUERY formal, ... recording the path to the current call
the type constructor or build tuple call currently being considered queryToCopy - a PRIM_QUERY formal ... recording the path to the current call
static void expandQueryForGenericTypeSpecifier(FnSymbol*  fn,
                                               std::vector<SymExpr*>& symExprs,
                                               ArgSymbol* formal,
                                               CallExpr* call,
                                               BaseAST* queried) {
  int position = 1;
  if (call->isNamed("_build_tuple")) {
    Expr*     actual = new SymExpr(new_IntSymbol(call->numActuals()));
    CallExpr* query  = makePrimQuery(queried, new_CStringSymbol("size"));
    addToWhereClause(fn, formal, new CallExpr("==", actual, query));
    call->baseExpr->replace(new SymExpr(dtTuple->symbol));
    position = position + 1; 
  } else if (call->isNamed("*")) {
    addToWhereClause(fn, formal, new CallExpr(PRIM_IS_STAR_TUPLE_TYPE, queried));
  } else if (call->isPrimitive(PRIM_TO_BORROWED_CLASS) ||
             call->isPrimitive(PRIM_TO_UNMANAGED_CLASS)) {
    bool borrowed = call->isPrimitive(PRIM_TO_BORROWED_CLASS);
    Type* parentType = borrowed?dtBorrowed:dtUnmanaged;
    addToWhereClause(fn, formal, new CallExpr(PRIM_IS_SUBTYPE_ALLOW_VALUES,
                                              parentType->symbol, queried));
    Type* theType = NULL;
    CallExpr* subCall = toCallExpr(call->get(1));
    if (subCall != NULL)
      if (SymExpr* subBase = toSymExpr(subCall->baseExpr))
        if (TypeSymbol* ts = toTypeSymbol(subBase->symbol()))
          theType = ts->type;
    if (theType == NULL)
      return;
    if (borrowed || !isClassLike(theType)) {
      call = toCallExpr(call->get(1));
    } else {
      Type* t = canonicalClassType(theType);
      AggregateType* at = toAggregateType(t);
      INT_ASSERT(at);
      Type* unm = at->getUnmanagedClass();
      subCall->baseExpr->replace(new SymExpr(unm->symbol));
      call->replace(subCall->remove());
      call = subCall;
    }
  }
  CallExpr* gatheringNamedArgs = makePrimQuery(queried);
  for_actuals(actual, call) {
    if (NamedExpr* named = toNamedExpr(actual)) {
      Symbol*   name = new_CStringSymbol(named->name);
      CallExpr* query = makePrimQuery(queried, name);
      gatheringNamedArgs->insertAtTail(new SymExpr(name));
      expandQueryForActual(fn, symExprs, formal, call, query, named->actual);
    }
  }
  for_actuals(actual, call) {
    if (isNamedExpr(actual) == false) {
      CallExpr* query = gatheringNamedArgs->copy();
      query->insertAtTail(new SymExpr(new_IntSymbol(position)));
      expandQueryForActual(fn, symExprs, formal, call, query, actual);
      position = position + 1;
    }
  }
}
static void expandQueryForGenericTypeSpecifier ( FnSymbol * fn , std :: vector < SymExpr * > & symExprs , ArgSymbol * formal , CallExpr * call , BaseAST * queried ) { int position = 1 ; if ( call -> isNamed ( " " ) ) { Expr * actual = new SymExpr ( new_IntSymbol ( call -> numActuals ( ) ) ) ; CallExpr * query = makePrimQuery ( queried , new_CStringSymbol ( " " ) ) ; addToWhereClause ( fn , formal , new CallExpr ( " " , actual , query ) ) ; call -> baseExpr -> replace ( new SymExpr ( dtTuple -> symbol ) ) ; position = position + 1 ; } else if ( call -> isNamed ( " " ) ) { addToWhereClause ( fn , formal , new CallExpr ( PRIM_IS_STAR_TUPLE_TYPE , queried ) ) ; } else if ( call -> isPrimitive ( PRIM_TO_BORROWED_CLASS ) || call -> isPrimitive ( PRIM_TO_UNMANAGED_CLASS ) ) { bool borrowed = call -> isPrimitive ( PRIM_TO_BORROWED_CLASS ) ; Type * parentType = borrowed ? dtBorrowed : dtUnmanaged ; addToWhereClause ( fn , formal , new CallExpr ( PRIM_IS_SUBTYPE_ALLOW_VALUES , parentType -> symbol , queried ) ) ; Type * theType = NULL ; CallExpr * subCall = toCallExpr ( call -> get ( 1 ) ) ; if ( subCall != NULL ) if ( SymExpr * subBase = toSymExpr ( subCall -> baseExpr ) ) if ( TypeSymbol * ts = toTypeSymbol ( subBase -> symbol ( ) ) ) theType = ts -> type ; if ( theType == NULL ) return ; if ( borrowed || ! isClassLike ( theType ) ) { call = toCallExpr ( call -> get ( 1 ) ) ; } else { Type * t = canonicalClassType ( theType ) ; AggregateType * at = toAggregateType ( t ) ; INT_ASSERT ( at ) ; Type * unm = at -> getUnmanagedClass ( ) ; subCall -> baseExpr -> replace ( new SymExpr ( unm -> symbol ) ) ; call -> replace ( subCall -> remove ( ) ) ; call = subCall ; } } CallExpr * gatheringNamedArgs = makePrimQuery ( queried ) ; for_actuals ( actual , call ) { if ( NamedExpr * named = toNamedExpr ( actual ) ) { Symbol * name = new_CStringSymbol ( named -> name ) ; CallExpr * query = makePrimQuery ( queried , name ) ; gatheringNamedArgs -> insertAtTail ( new SymExpr ( name ) ) ; expandQueryForActual ( fn , symExprs , formal , call , query , named -> actual ) ; } } for_actuals ( actual , call ) { if ( isNamedExpr ( actual ) == false ) { CallExpr * query = gatheringNamedArgs -> copy ( ) ; query -> insertAtTail ( new SymExpr ( new_IntSymbol ( position ) ) ) ; expandQueryForActual ( fn , symExprs , formal , call , query , actual ) ; position = position + 1 ; } } }
call - the type constructor or build tuple call currently being considered
queryToCopy - a PRIM_QUERY formal, ... recording the path to the current call
call - the type constructor or build tuple call currently being considered queryToCopy - a PRIM_QUERY formal ... recording the path to the current call
// Add check that actual tuple size == formal tuple size // tuple size is technically 1st param/type // it happens to be that 1st actual == size so that will be checked below // Check that whatever it has right borrow / unmanaged nature // Match on an inner call to a TypeSymbol // pattern of call to TypeSymbol not found, stop here // Only work with theType being unmanaged or class type // e.g. if it's a record, we just ignore the PRIM_TO_... // For nested calls in PRIM_TO_BORROWED_CLASS, // proceed as if the PRIM_TO_BORROWED_CLASS wasn't // there. That's because the borrowed class is the // 'canonical' class representation used in the compiler. // This branch also applies to say `unmanaged MyRecord(?t)` // For nested calls in PRIM_TO_UNMANAGED_CLASS, where the // called type is a class or an unmanaged class. // Replace PRIM_TO_UNMANAGED( MyClass( Def ?t ) ) // with // unmanaged MyClass ( Def ?t ) // This can't be applied generally in scopeResolve b/c // of the way type constructors are currently normalized. // not a NamedExpr? handled in next loop.