Fixes for ~shannon/CHAPEL/chapel/test/trivial/shannon/assignment_expr.chpl

git-svn-id: 88467cb1fb04b8a755be7e1ee1026be4190196ef@299 3a8e244f-b0f2-452b-bcba-4c88e055c3ca

// Chapel Prelude

in system __name "system"; // system module

// builtin types

type symbol __name "symbol";
type function __name "function";
type module __name "module";
type continuation __name "continuation";
type any __name "any";
type vector __name "vector";
type tuple __name "tuple";
type void __name "void" : tuple;
type object __name "object" = { };
type list __name "list";
type ref __name "ref";
type value __name "value";

type catagory __name "catagory";
type set __name "set" : catagory;

type integer8 __name "int8";
type integer16 __name "int16";
type integer32 __name "int32";
type integer64 __name "int64";
type integer __name "int" = integer64;
type uinteger8 __name "uint8";
type uinteger16 __name "uint16";
type uinteger32 __name "uint32";
type uinteger64 __name "uint64";
type uinteger __name "uint" = uinteger32;
type anyinteger __name "anyint" =
  integer8 | integer16 | integer32 | integer64 |
  uinteger8 | uinteger16 | uinteger32 | uinteger64;

type float32 __name "float32";
type float64 __name "float64";
type float80 __name "float80";
type float128 __name "float128";
type float __name "float" = float64;
type anyfloat __name "anyfloat" =
  float32 | float64 | float80 | float128;

type anynum __name "anynum" = anyinteger | anyfloat;
type char __name "char" = uinteger8;
type size __name "size" = uinteger;
type bool __name "bool" = integer;
type string __name "string";
type enum_element __name "enum_element" = integer;

// builtin value

null __name "null" : ();

// global initialization function

__init__ __name "init" : 0;

//   public internal function
var reply = #reply __name "reply";

// builtin symbols
#__make_tuple __name "make_tuple";
#__make_list __name "make_list";
#__make_vector __name "make_vector";
#__make_set __name "make_set";
#__make_continuation __name "make_continuation";
#__primitive __name "primitive";
#__new __name "new";
#__index __name "index";
#__print __name "print";
#operator __name "operator";
#"&" __name "doref";
#"=" __name "assign";

// overloadable primitive operators
function new(a:any) { #__new ^^ a; }
function operator(a:any, #".", b:symbol)	{ #__primitive ^^ a ^^ #"." ^^ b }
function operator(a:any, #"*.", b:symbol)	{ #__primitive ^^ a ^^ #"." ^^ b }
function operator(a:anynum, #"*", b:anynum)	{ #__primitive ^^ a ^^ #"*" ^^ b }
function operator(a:anynum, #"/", b:anynum)	{ #__primitive ^^ a ^^ #"/" ^^ b }
function operator(a:anynum, #"%", b:anynum)	{ #__primitive ^^ a ^^ #"%" ^^ b }
function operator(a:anynum, #"+", b:anynum)	{ #__primitive ^^ a ^^ #"+" ^^ b }
function operator(a:anynum, #"-", b:anynum)	{ #__primitive ^^ a ^^ #"-" ^^ b }
function operator(a:integer, #"<<", b:integer)	{ #__primitive ^^ a ^^ #"<<" ^^ b }
function operator(a:integer, #">>", b:integer)	{ #__primitive ^^ a ^^ #">>" ^^ b }
function operator(a:anynum, #"<", b:anynum)	{ #__primitive ^^ a ^^ #"<" ^^ b }
function operator(a:anynum, #"<=", b:anynum)	{ #__primitive ^^ a ^^ #"<=" ^^ b }
function operator(a:anynum, #">", b:anynum)	{ #__primitive ^^ a ^^ #">" ^^ b }
function operator(a:anynum, #">=", b:anynum)	{ #__primitive ^^ a ^^ #">=" ^^ b }
function operator(a:anynum, #"==", b:anynum)	{ #__primitive ^^ a ^^ #"==" ^^ b }
function operator(a:anynum, #"!=", b:anynum)	{ #__primitive ^^ a ^^ #"!=" ^^ b }
function operator(a:integer, #"&", b:integer)	{ #__primitive ^^ a ^^ #"&" ^^ b }
function operator(a:integer, #"^", b:integer)	{ #__primitive ^^ a ^^ #"^" ^^ b }
function operator(a:integer, #"|", b:integer)	{ #__primitive ^^ a ^^ #"|" ^^ b }
function operator(a:any, #"&&", b:any)		{ #__primitive ^^ a ^^ #"&&" ^^ b }
function operator(a:any, #"||", b:any)		{ #__primitive ^^ a ^^ #"||" ^^ b }
function operator(a:ref, #"=", b:any)		{ #__primitive ^^ a ^^ #"=" ^^ b }
function operator(a:any, #"=", b:any)		{ b }
//function operator(a:value, #"=", b:value)	{ numeric assignment }
function operator(a:anynum, #"*=", b:anynum)	{ #__primitive ^^ a ^^ #"*" ^^ b }
function operator(a:anynum, #"/=", b:anynum)	{ #__primitive ^^ a ^^ #"/" ^^ b }
function operator(a:anynum, #"%=", b:anynum)	{ #__primitive ^^ a ^^ #"%" ^^ b }
function operator(a:anynum, #"+=", b:anynum)	{ #__primitive ^^ a ^^ #"+" ^^ b }
function operator(a:anynum, #"-=", b:anynum)	{ #__primitive ^^ a ^^ #"-" ^^ b }
function operator(a:anynum, #"<<=", b:integer)	{ #__primitive ^^ a ^^ #"<<" ^^ b }
function operator(a:anynum, #">>=", b:integer)	{ #__primitive ^^ a ^^ #">>" ^^ b }
function operator(a:anynum, #"&=", b:integer)	{ #__primitive ^^ a ^^ #"&" ^^ b }
function operator(a:anynum, #"|=", b:integer)	{ #__primitive ^^ a ^^ #"|" ^^ b }
function operator(a:anynum, #"^=", b:integer)	{ #__primitive ^^ a ^^ #"^" ^^ b }
function operator(a:any, #"->", b:symbol)	{ #__primitive ^^ (#__primitive ^^ #"*" ^^ a) ^^ #"." ^^ b }
function operator(a:any, #"->*", b:symbol)	{ #__primitive ^^ (#__primitive ^^ #"*" ^^ a) ^^ #"." ^^ b }
function operator(a:anynum, #"^^", b:anynum)	{ #__primitive ^^ a ^^ #"^^" ^^ b }
function operator(#"++", a:anynum)		{ #__primitive ^^ a ^^ #"+" ^^ 1 }
function operator(#"--", a:anynum)		{ #__primitive ^^ a ^^ #"-" ^^ 1 }
function operator(#"+", a:anynum)		{ #__primitive ^^ #"+" ^^ a }
function operator(#"-", a:anynum)		{ #__primitive ^^ #"-" ^^ a }
function operator(#"~", a:anynum)		{ #__primitive ^^ #"~" ^^ a }
function operator(#"!", a:any)			{ #__primitive ^^ #"!" ^^ a }
function operator(#"*", a:any)			{ #__primitive ^^ #"*" ^^ a }
function operator(#"&", var a:any)		{ #__primitive ^^ #"&" ^^ a }
function operator(a:anynum, #"|", b:anynum)	{ #__primitive ^^ a ^^ #"|" ^^ b }
function operator(#"(", a:symbol, b:any)	{ #__primitive ^^ #"(" ^^ a ^^ b }
function operator(a:anynum, #"++")		{ #__primitive ^^ a ^^ #"+" ^^ 1 }
function operator(a:anynum, #"--")		{ #__primitive ^^ a ^^ #"-" ^^ 1 }

// arrays

type sequence __name "sequence";
type domain __name "domain";
type array __name "array";
class locale {};

var Locales = new locale;

class distribution {
  type source_domain : domain;
  type destination_domain : domain;
  var source : source_domain;
  var destination : destination_domain;
  function local(i : sequence) : sequence;
  function offset(i : sequence) : sequence;
}

class cyclic implements distribution {
  var width : integer;
}

var block2 = new distribution;
function distribution::class(d:distribution, l:locale) { d }

value domain(rank, distribute, target) : vector {
  const rank : integer;
  const index : sequence;
  type target : domain;
  type distribute: distribution;
}

function domain::class(s1 : sequence) {
  var d = new domain;
  d.rank = 1;
  d.index = s1;
  return d;
}

function domain::class(s1 : sequence, s2 : sequence) {
  var d = new domain;
  d.rank = 2;
  d.index = new sequence;
  d.index.first = s1.first * s2.first;
  d.index.last = s1.last * s2.last;
  d.index.step = s1.step * s2.step;
  return d;
}

function domain::class(s : sequence, d : distribution) {
  domain(s)
}

class sequence {
  const rank : integer;
  const first : tuple;
  const last : tuple;
  const step : tuple;
}

function sequence::class afirst alast astep {
  var s = new sequence;
  s.rank = 1;
  s.first = afirst;
  s.last = alast;
  s.step = astep;
  return s;
}

function operator(a:sequence, #"*", b:sequence) {
  new sequence
}

function vector::self s { #__index ^^ self ^^ s }
function domain::self s { new domain }

value array {
  var d : domain;
  var v : vector;
}

function array::self s { #__index ^^ self ^^ s }

function array::class dd e {
  var a = new array;
  a.d = dd;
  a.v = (#__make_vector ^^ dd.rank);
  (#__index ^^ a.v ^^ 0) = e;
  return a;
}

function array::class dd {
  var a = new array;
  a.d = dd;
  a.v = (#__make_vector ^^ dd.rank);
  return a;
}

function operator(a:array, s:symbol, b:array) {
  operator(a.v(0), s, b.v(0));
}

function reshape(l:locale, s:sequence) { l }

function write(a) { 0 }
function writeln(a) { 0 }
function print(a) { #__print ^^ a; }

/*
  David's old iterator and domain examples

// iterators

type iterator(a);
type iteratable = {
  type element_type;
  elements : iterator(element_type);
};

// domains

type domain;
type sequence __name "sequence";
type decomposition;
type arithmetic_domain(rank:symbol, distribute:decomposition, to:domain) : domain;
type opaque_domain(distribute:decomposition, to:domain) : domain;
type index(a:domain);
type subdomain(a:domain) = {
  size : integer;
  lbound : integer -> integer;
  ubound : integer -> integer;
};

type decomposition : catagory = {
  type source : domain, target : domain;
  locale : index(source) -> index(target);
};

type simple_block_decomposition : decomposition = {
  where source : arithmetic_domain(1), target : arithmetic_domain(1);
  s : source;
  t : target;
  chunk : integer;
  mod : integer;
};

simple_block_decomposition::local(i): {
  k : i / chunk;
  k : (i - s.lbound(1)) / chunk;
  if (k < mod)
    k += 1;
  k + t.lbound(1)
};

type map(d: domain, a) : iteratable = {
  elements : iterator(a);
  indexes : iterator(index(d));
  operator: #"[" * index(d) -> a &;
};

operator(a:map, #"[", b:index(map::d)): 0;
*/

// Chapel Prelude

in system __name "system"; // system module

// builtin types

type symbol __name "symbol";
type function __name "function";
type module __name "module";
type continuation __name "continuation";
type any __name "any";
type vector __name "vector";
type tuple __name "tuple";
type void __name "void" : tuple;
type object __name "object" = { };
type list __name "list";
type ref __name "ref";
type value __name "value";

type catagory __name "catagory";
type set __name "set" : catagory;

type integer8 __name "int8";
type integer16 __name "int16";
type integer32 __name "int32";
type integer64 __name "int64";
type integer __name "int" = integer64;
type uinteger8 __name "uint8";
type uinteger16 __name "uint16";
type uinteger32 __name "uint32";
type uinteger64 __name "uint64";
type uinteger __name "uint" = uinteger32;
type anyinteger __name "anyint" =
  integer8 | integer16 | integer32 | integer64 |
  uinteger8 | uinteger16 | uinteger32 | uinteger64;

type float32 __name "float32";
type float64 __name "float64";
type float80 __name "float80";
type float128 __name "float128";
type float __name "float" = float64;
type anyfloat __name "anyfloat" =
  float32 | float64 | float80 | float128;

type anynum __name "anynum" = anyinteger | anyfloat;
type char __name "char" = uinteger8;
type size __name "size" = uinteger;
type bool __name "bool" = integer;
type string __name "string";
type enum_element __name "enum_element" = integer;

// builtin value

null __name "null" : ();

// global initialization function

__init__ __name "init" : 0;

//   public internal function
var reply = #reply __name "reply";

// builtin symbols
#__make_tuple __name "make_tuple";
#__make_list __name "make_list";
#__make_vector __name "make_vector";
#__make_set __name "make_set";
#__make_continuation __name "make_continuation";
#__primitive __name "primitive";
#__new __name "new";
#__index __name "index";
#__print __name "print";
#operator __name "operator";
#"&" __name "doref";
#"=" __name "assign";

// overloadable primitive operators
function new(a:any) { #__new ^^ a; }
function operator(a:any, #".", b:symbol)	{ #__primitive ^^ a ^^ #"." ^^ b }
function operator(a:any, #"*.", b:symbol)	{ #__primitive ^^ a ^^ #"." ^^ b }
function operator(a:anynum, #"*", b:anynum)	{ #__primitive ^^ a ^^ #"*" ^^ b }
function operator(a:anynum, #"/", b:anynum)	{ #__primitive ^^ a ^^ #"/" ^^ b }
function operator(a:anynum, #"%", b:anynum)	{ #__primitive ^^ a ^^ #"%" ^^ b }
function operator(a:anynum, #"+", b:anynum)	{ #__primitive ^^ a ^^ #"+" ^^ b }
function operator(a:anynum, #"-", b:anynum)	{ #__primitive ^^ a ^^ #"-" ^^ b }
function operator(a:integer, #"<<", b:integer)	{ #__primitive ^^ a ^^ #"<<" ^^ b }
function operator(a:integer, #">>", b:integer)	{ #__primitive ^^ a ^^ #">>" ^^ b }
function operator(a:anynum, #"<", b:anynum)	{ #__primitive ^^ a ^^ #"<" ^^ b }
function operator(a:anynum, #"<=", b:anynum)	{ #__primitive ^^ a ^^ #"<=" ^^ b }
function operator(a:anynum, #">", b:anynum)	{ #__primitive ^^ a ^^ #">" ^^ b }
function operator(a:anynum, #">=", b:anynum)	{ #__primitive ^^ a ^^ #">=" ^^ b }
function operator(a:anynum, #"==", b:anynum)	{ #__primitive ^^ a ^^ #"==" ^^ b }
function operator(a:anynum, #"!=", b:anynum)	{ #__primitive ^^ a ^^ #"!=" ^^ b }
function operator(a:integer, #"&", b:integer)	{ #__primitive ^^ a ^^ #"&" ^^ b }
function operator(a:integer, #"^", b:integer)	{ #__primitive ^^ a ^^ #"^" ^^ b }
function operator(a:integer, #"|", b:integer)	{ #__primitive ^^ a ^^ #"|" ^^ b }
function operator(a:any, #"&&", b:any)		{ #__primitive ^^ a ^^ #"&&" ^^ b }
function operator(a:any, #"||", b:any)		{ #__primitive ^^ a ^^ #"||" ^^ b }
function operator(a:ref, #"=", b:any)		{ #__primitive ^^ a ^^ #"=" ^^ b }
function operator(a:any, #"=", b:any)		{ b }
//function operator(a:value, #"=", b:value)	{ numeric assignment }
function operator(a:ref, #"*=", b:anynum)	{ #__primitive ^^ #"*" ^^ b }
function operator(a:ref, #"/=", b:anynum)	{ #__primitive ^^ a ^^ #"/" ^^ b }
function operator(a:ref, #"%=", b:anynum)	{ #__primitive ^^ a ^^ #"%" ^^ b }
function operator(a:ref, #"+=", b:anynum)	{ #__primitive ^^ a ^^ #"+" ^^ b }
function operator(a:ref, #"-=", b:anynum)	{ #__primitive ^^ a ^^ #"-" ^^ b }
function operator(a:ref, #"<<=", b:integer)	{ #__primitive ^^ a ^^ #"<<" ^^ b }
function operator(a:ref, #">>=", b:integer)	{ #__primitive ^^ a ^^ #">>" ^^ b }
function operator(a:ref, #"&=", b:integer)	{ #__primitive ^^ a ^^ #"&" ^^ b }
function operator(a:ref, #"|=", b:integer)	{ #__primitive ^^ a ^^ #"|" ^^ b }
function operator(a:ref, #"^=", b:integer)	{ #__primitive ^^ a ^^ #"^" ^^ b }
function operator(a:any, #"->", b:symbol)	{ #__primitive ^^ (#__primitive ^^ #"*" ^^ a) ^^ #"." ^^ b }
function operator(a:any, #"->*", b:symbol)	{ #__primitive ^^ (#__primitive ^^ #"*" ^^ a) ^^ #"." ^^ b }
function operator(a:anynum, #"^^", b:anynum)	{ #__primitive ^^ a ^^ #"^^" ^^ b }
function operator(#"++", a:ref)			{ #__primitive ^^ a ^^ #"+" ^^ 1 }
function operator(#"--", a:ref)			{ #__primitive ^^ a ^^ #"-" ^^ 1 }
function operator(#"+", a:anynum)		{ #__primitive ^^ #"+" ^^ a }
function operator(#"-", a:anynum)		{ #__primitive ^^ #"-" ^^ a }
function operator(#"~", a:anynum)		{ #__primitive ^^ #"~" ^^ a }
function operator(#"!", a:any)			{ #__primitive ^^ #"!" ^^ a }
function operator(#"*", a:any)			{ #__primitive ^^ #"*" ^^ a }
function operator(#"&", var a:any)		{ #__primitive ^^ #"&" ^^ a }
function operator(a:anynum, #"|", b:anynum)	{ #__primitive ^^ a ^^ #"|" ^^ b }
function operator(#"(", a:symbol, b:any)	{ #__primitive ^^ #"(" ^^ a ^^ b }
function operator(a:ref, #"++")			{ #__primitive ^^ a ^^ #"+" ^^ 1 }
function operator(a:ref, #"--")			{ #__primitive ^^ a ^^ #"-" ^^ 1 }

// arrays

type sequence __name "sequence";
type domain __name "domain";
type array __name "array";
class locale {};

var Locales = new locale;

class distribution {
  type source_domain : domain;
  type destination_domain : domain;
  var source : source_domain;
  var destination : destination_domain;
  function local(i : sequence) : sequence;
  function offset(i : sequence) : sequence;
}

class cyclic implements distribution {
  var width : integer;
}

var block2 = new distribution;
function distribution::class(d:distribution, l:locale) { d }

value domain(rank, distribute, target) : vector {
  const rank : integer;
  const index : sequence;
  type target : domain;
  type distribute: distribution;
}

function domain::class(s1 : sequence) {
  var d = new domain;
  d.rank = 1;
  d.index = s1;
  return d;
}

function domain::class(s1 : sequence, s2 : sequence) {
  var d = new domain;
  d.rank = 2;
  d.index = new sequence;
  d.index.first = s1.first * s2.first;
  d.index.last = s1.last * s2.last;
  d.index.step = s1.step * s2.step;
  return d;
}

function domain::class(s : sequence, d : distribution) {
  domain(s)
}

class sequence {
  const rank : integer;
  const first : tuple;
  const last : tuple;
  const step : tuple;
}

function sequence::class afirst alast astep {
  var s = new sequence;
  s.rank = 1;
  s.first = afirst;
  s.last = alast;
  s.step = astep;
  return s;
}

function operator(a:sequence, #"*", b:sequence) {
  new sequence
}

function vector::self s { #__index ^^ self ^^ s }
function domain::self s { new domain }

value array {
  var d : domain;
  var v : vector;
}

function array::self s { #__index ^^ self ^^ s }

function array::class dd e {
  var a = new array;
  a.d = dd;
  a.v = (#__make_vector ^^ dd.rank);
  (#__index ^^ a.v ^^ 0) = e;
  return a;
}

function array::class dd {
  var a = new array;
  a.d = dd;
  a.v = (#__make_vector ^^ dd.rank);
  return a;
}

function operator(a:array, s:symbol, b:array) {
  operator(a.v(0), s, b.v(0));
}

function reshape(l:locale, s:sequence) { l }

function write(a) { 0 }
function writeln(a) { 0 }
function print(a) { #__print ^^ a; }

/*
  David's old iterator and domain examples

// iterators

type iterator(a);
type iteratable = {
  type element_type;
  elements : iterator(element_type);
};

// domains

type domain;
type sequence __name "sequence";
type decomposition;
type arithmetic_domain(rank:symbol, distribute:decomposition, to:domain) : domain;
type opaque_domain(distribute:decomposition, to:domain) : domain;
type index(a:domain);
type subdomain(a:domain) = {
  size : integer;
  lbound : integer -> integer;
  ubound : integer -> integer;
};

type decomposition : catagory = {
  type source : domain, target : domain;
  locale : index(source) -> index(target);
};

type simple_block_decomposition : decomposition = {
  where source : arithmetic_domain(1), target : arithmetic_domain(1);
  s : source;
  t : target;
  chunk : integer;
  mod : integer;
};

simple_block_decomposition::local(i): {
  k : i / chunk;
  k : (i - s.lbound(1)) / chunk;
  if (k < mod)
    k += 1;
  k + t.lbound(1)
};

type map(d: domain, a) : iteratable = {
  elements : iterator(a);
  indexes : iterator(index(d));
  operator: #"[" * index(d) -> a &;
};

operator(a:map, #"[", b:index(map::d)): 0;
*/


Capturing other code review comments into BradsBlock1DPar.chpl

Either by fixing them, or by adding TODOs/comments.

git-svn-id: 88467cb1fb04b8a755be7e1ee1026be4190196ef@14431 3a8e244f-b0f2-452b-bcba-4c88e055c3ca

// TODO: Make this work for a strided domain of locales; for a strided
// domain implemented using this distribution.

// TODO: Have the global class leader/follower iterators defer to the
// local class leader/followers once we're within a locale?

// TODO: Make these into an official distribution?

// TODO: Label which routines are the compiler's interface vs. an
// internal interface.

// TODO: Label the linkage fields.

// TODO: implement the slicing interface?

config param debugBradsBlock1D = false;

// TODO: This would need to be moved somewhere more standard
enum IteratorType { leader, follower };

//
// The distribution class
//
class Block1DDist {
  //
  // The distribution's index type and domain's global index type
  //
  type idxType = int(64);

  //
  // The bounding box that defines the block distribution
  //
  const boundingBox: domain(1, idxType);

  //
  // a domain and array describing the set of target locales to which
  // the indices are mapped
  //
  const targetLocDom: domain(1);
  const targetLocs: [targetLocDom] locale;
  //
  // NOTE: originally I wrote this as:
  //
  //   const targetLocs = Locales;
  //   const targetLocDom = targetLocs.domain;
  //
  // but this had two interesting problems:
  //
  // (1) the capture of the targetLocs array only makes a copy of the
  //     array, not of its domain, so if someone were to resize the
  //     LocaleSpace domain outside of the class, this would inadvertantly
  //     get resized as well.  We really want to make a copy of both the
  //     domain and array (which I now do in the constructor).
  //
  // (2) Initializing targetLocs with Locales prevents us from assigning
  //     anything other than a numLocales-ary array of locales to it
  //     which is stricter than I wanted -- I only wanted to restrict
  //     us to a 1D array of locales.  In our current model, this would
  //     require us to have some sort of [domain(1)] locale declaration
  //     to make it work.  Or we could think about whether a model in
  //     which only the array's static type information is inferred
  //     for a field?

  //
  // an array of local distribution class descriptors -- set up in
  // initialize() below
  //
  // TODO: would like this to be const and initialize in-place,
  // removing the initialize method; would want to be able to use
  // an on-clause at the expression list to make this work.
  // Otherwise, would have to move the allocation into a function
  // just to get it at the statement level.
  //
  // WANTED:
  //
  /*
  const locDist: [loc in targetLocDom] LocBlock1DDist(idxType)
                   = on targetLocs(loc) do
                       new LocBlock1DDist(idxType, targetLocDom.order(loc), this);
  */
  //
  // but this doesn't work yet because an array forall initializer
  // apparently can't refer to a local member domain.
  //
  const locDist: [targetLocDom] LocBlock1DDist(idxType);
  //
  // WORKAROUND: Initialize in the constructor instead
  //

  //
  // TODO: 0-base the target locales domain in the constructor rather
  // than whenever it's used for simplicity?
  //
  def Block1DDist(type idxType = int(64), bbox: domain(1, idxType),
                  targetLocales: [?targetLocalesDomain] locale = Locales) {
    boundingBox = bbox;
    targetLocDom = targetLocalesDomain;
    targetLocs = targetLocales;
    //
    // WANT TO DO:
    /*
    for locid in targetLocDom do
      on targetLocs(locid) do
        locDist(locid) = new LocBlock1DDist(idxType, locid, this);
    */
    //
    // BUT results in a _heapAlloc(type int(64)) call.
    // WORKAROUND:
    helpConstruct();
  }
  //
  // WORKAROUND CONTINUED:
  //
  def helpConstruct() {
    for locid in targetLocDom do
      on targetLocs(locid) do
        locDist(locid) = new LocBlock1DDist(idxType, locid, this);
  }
  //
  // END WORKAROUND
  //

  def writeThis(x:Writer) {
    x.writeln("BradsBlock1DPar");
    x.writeln("---------------");
    x.writeln("distributes: ", boundingBox);
    x.writeln("across locales: ", targetLocs);
    x.writeln("indexed via: ", targetLocDom);
    x.writeln("resulting in: ");
    for locid in targetLocDom do
      x.writeln("  [", locid, "] ", locDist(locid));
  }

  //
  // Create a new domain over this distribution with the given index
  // set (inds) and global index type (idxType, idxType)
  //
  // TODO: What would we do if domIdxType did not match idxType?
  //
  def newDomain(inds, type domIdxType = idxType) where domIdxType == idxType {
    return new Block1DDom(idxType, this, inds);
  }

  //
  // compute what chunk of inds is owned by a given locale -- assumes
  // it's being called on the locale in question
  //
  def getChunk(inds, locid) {
    // use domain slicing to get the intersection between what the
    // locale owns and the domain's index set

    // TODO: Should this be able to be written as myChunk[inds] ???
    return locDist(locid).myChunk(inds.dim(1));
  }

  //
  // Determine which locale owns a particular index
  //
  // TODO: If targetLocsDom was 0-based, would this function be easier?
  //
  // TODO: I jotted down a note during the code review asking whether
  // targetLocs.numElements and boundingbox.numIndices should be
  // captured locally, or captured in the default dom/array implementation
  // or inlined.  Not sure what that point was anymore, though.
  //
  def ind2locInd(ind: idxType) {
    const ind0 = ind - boundingBox.low;
    const loc0 = (ind0 * targetLocs.numElements) / boundingBox.numIndices;
    const locInd = loc0: index(targetLocs.domain) + targetLocs.domain.low;
    return locInd;
  }

  def ind2loc(ind: idxType) {
    return targetLocs(ind2locInd(ind));
  }
}

//
// A per-locale local distribution class
//
class LocBlock1DDist {
  //
  // The distribution's index type and domain's global index type
  //
  type idxType;

  //
  // This stores the piece of the global bounding box owned by
  // the locale.  Note that my original guess that we'd want
  // to use lclIdxType here is wrong since we're talking about
  // the section of the global index space owned by the locale.
  //
  // TODO: Rename locid -- it's not very clear
  //
  const myChunk: domain(1, idxType);
  const locid: int;
  const loc: locale;

  //
  // Compute what chunk of index(1) is owned by the current locale
  // Arguments:
  //
  def LocBlock1DDist(type idxType,
                     _locid: int, // the locale index from the target domain
                     dist: Block1DDist(idxType) // reference to glob dist
                     ) {
    locid = _locid;
    loc = dist.targetLocs(locid);
    //
    // TODO -- assert that "loc == here" at this point for safety?
    //
    const lo = dist.boundingBox.low;
    const hi = dist.boundingBox.high;
    const numelems = hi - lo + 1;
    const numlocs = dist.targetLocDom.numIndices;
    const locid0 = dist.targetLocDom.order(locid); // 0-based locale ID
    const blo = if (locid0 == 0) then min(idxType)
                else procToData((numelems: real * locid0) / numlocs, lo);
    const bhi = if (locid0 == numlocs - 1) then max(idxType)
                else procToData((numelems: real * (locid0+1)) / numlocs, lo) - 1;
    myChunk = [blo..bhi];
    if debugBradsBlock1D then
      writeln(this);
  }

  //
  // a helper function for mapping processors to indices
  //
  def procToData(x, lo)
    return (lo + (x: lo.type) + (x:real != x:int:real));

  def writeThis(x:Writer) {
    x.write("locale ", loc.id, " owns chunk: ", myChunk);
  }
}

//
// The global domain class
//
class Block1DDom {
  //
  // The index types of the domain
  //
  type idxType;

  //
  // a pointer to the parent distribution
  //
  const dist: Block1DDist(idxType);

  //
  // a domain describing the complete domain
  //
  const whole: domain(1, idxType);

  //
  // an array of local domain class descriptors -- set up in
  // initialize() below
  //
  //
  // TODO: would like this to be const and initialize in-place,
  // removing the initialize method; would want to be able to use
  // an on-clause at the expression list to make this work.
  // Otherwise, would have to move the allocation into a function
  // just to get it at the statement level.
  //
  var locDoms: [dist.targetLocDom] LocBlock1DDom(idxType);

  def initialize() {
    for locid in dist.targetLocDom do
      on dist.targetLocs(locid) do
        locDoms(locid) = new LocBlock1DDom(idxType, this,
                                           dist.getChunk(whole, locid));
    if debugBradsBlock1D then
      [loc in dist.targetLocDom] writeln(loc, " owns ", locDoms(loc));
  }

  //
  // the iterator for the domain -- currently sequential
  //
  def these() {
    for blk in locDoms do
      // TODO: Would want to do something like:
      // on blk do
      // But can't currently have yields in on clauses
        for ind in blk do
          yield ind;
  }

  //
  // this is the parallel iterator for the global domain, following
  // a variation on Steve and David's proposals -- I've split the
  // single iterator into two iterators, distinguished by where
  // clauses on their parameter values.  This permits each to only
  // take the parameters it cares about; permits the leader to be
  // defined in an inlineable way; and permits the follower for an
  // array iterator to be a var iterator
  //
  // I've named these methods newThese() for the time being
  // to avoid conflicting with the above which is currently targeted
  // by the compiler.  My current assumption is that we would want to
  // overload these() to serve this purpose in the final language
  // definition.
  //
  // TODO: Steve's question: how would a leader containing an on
  // clause interact with a loop that used an on clause explicitly
  // within its body?  How would it be done efficiently?
  //
  def newThese(param iterator: IteratorType)
        where iterator == IteratorType.leader {
    //
    // TODO: This currently only results in a single level of
    // per-locale parallelism -- no per-core parallelism; maybe
    // approach this by deferring to the local leader/follower
    // iterators at some point?
    //
    // TODO: Really want the parallelism across the target locales
    // to be expressed more independently of the distribution by
    // pushing it into the leader iterator.  Need to get an on clause
    // into here somehow.  That is:
    //
    //   coforall locDom in locDoms do
    //     on locDom do
    //       yield locDom.myBlock - whole.low;
    //
    // TODO: And really want to split the inter- and intra-locale
    // parallelism into two separate stages for communication
    // optimization and the like
    //
    // TODO: Abstract this subtraction of low into a function?
    // Note relationship between this operation and the
    // order/position functions -- any chance for creating similar
    // support? (esp. given how frequent this seems likely to be?)
    //
    for locDom in locDoms do
      yield locDom.myBlock - whole.low;
  }

  def newThese(param iterator: IteratorType, followThis)
        where iterator == IteratorType.follower {
    //
    // TODO: Abstract this addition of low into a function?
    // Note relationship between this operation and the
    // order/position functions -- any chance for creating similar
    // support? (esp. given how frequent this seems likely to be?)
    //
    // TODO: Is there some clever way to invoke the leader/follower
    // iterator on the local blocks in here such that the per-core
    // parallelism is expressed at that level?  Seems like a nice
    // natural composition and might help with my fears about how
    // stencil communication will be done on a per-locale basis.
    for i in followThis {
      yield i + whole.low;
    }
  }

  //
  // the print method for the domain
  //
  def writeThis(x:Writer) {
    x.write(whole);
  }

  //
  // how to allocate a new array over this domain
  //
  def newArray(type elemType) {
    return new Block1DArr(idxType, elemType, this);
  }

  //
  // queries for the number of indices, low, and high bounds
  //
  def numIndices {
    return whole.numIndices;
  }

  def low {
    return whole.low;
  }

  def high {
    return whole.high;
  }
}

//
// the local domain class
//
class LocBlock1DDom {
  //
  // The index type of the domain
  //
  type idxType;

  //
  // a reference to the parent global domain class
  //
  const wholeDom: Block1DDom(idxType);

  //
  // a local domain describing the indices owned by this locale
  //
  //
  // TODO: I used to use a local index type for this, but that would
  // require a glbIdxType offset in order to get from the global
  // indices back to the local index type.
  //
  // TODO: Steve would like to see the strided parameter pushed into
  // the global and local domain classes.
  //
  var myBlock: domain(1, idxType);

  //
  // iterator over this locale's indices
  //
  def these() {
    // May want to do something like:
    // on this do
    // But can't currently have yields in on clauses
    for ind in myBlock do
      yield ind;
  }

  //
  // this is the parallel iterator for the local domain, see global
  // domain parallel iterators for general notes on the approach
  //
  def newThese(param iterator: IteratorType)
        where iterator == IteratorType.leader {
  }

  def newThese(param iterator: IteratorType, followThis)
        where iterator == IteratorType.follower {
  }

  //
  // how to write out this locale's indices
  //
  def writeThis(x:Writer) {
    x.write(myBlock);
  }

  //
  // queries for this locale's number of indices, low, and high bounds
  //
  // TODO: Are these used internally only?
  //
  def numIndices {
    return myBlock.numIndices;
  }

  def low {
    return myBlock.low;
  }

  def high {
    return myBlock.high;
  }
}

//
// the global array class
//
class Block1DArr {
  //
  // The index type of the domain
  //
  type idxType;

  //
  // the array's element type
  //
  type elemType;

  //
  // the global domain descriptor for this array
  //
  var dom: Block1DDom(idxType);

  //
  // an array of local array classes
  //
  // TODO: would like this to be const and initialize in-place,
  // removing the initialize method; would want to be able to use
  // an on-clause at the expression list to make this work.
  // Otherwise, would have to move the allocation into a function
  // just to get it at the statement level.
  //
  var locArr: [dom.dist.targetLocDom] LocBlock1DArr(idxType, elemType);

  def initialize() {
    for locid in dom.dist.targetLocDom do
      on dom.dist.targetLocs(locid) do
        locArr(locid) = new LocBlock1DArr(idxType, elemType, dom.locDoms(locid));
  }

  //
  // the global accessor for the array
  //
  // TODO: Do we need a global bounds check here or in ind2locind?
  //
  def this(i: idxType) var {
    return locArr(dom.dist.ind2locInd(i))(i);
  }

  //
  // the iterator over the array's elements, currently sequential
  //
  def these() var {
    for loc in dom.dist.targetLocDom {
      // TODO: May want to do something like:
      // on this do
      // But can't currently have yields in on clauses
      for elem in locArr(loc) {
        yield elem;
      }
    }
  }

  //
  // this is the parallel iterator for the global array, see th
  // example for general notes on the approach
  //

  def newThese(param iterator: IteratorType)
        where iterator == IteratorType.leader {
    for blk in dom.newThese(IteratorType.leader) do
      yield blk;
  }

  def newThese(param iterator: IteratorType, followThis) var
        where iterator == IteratorType.follower {
    for i in followThis {
      yield this(i + dom.low);
    }
  }

  //
  // how to print out the whole array, sequentially
  //
  def writeThis(x: Writer) {
    var first = true;
    for loc in dom.dist.targetLocDom {
      // May want to do something like the following:
      //      on loc {
      // but it causes deadlock -- see writeThisUsingOn.chpl
        if (locArr(loc).numElements >= 1) {
          if (first) {
            first = false;
          } else {
            x.write(" ");
          }
          x.write(locArr(loc));
        }
        //    }
      stdout.flush();
    }
  }

  //
  // a query for the number of elements in the array
  //
  def numElements {
    return dom.numIndices;
  }
}

//
// the local array class
//
class LocBlock1DArr {
  //
  // The index type of the domain
  //
  type idxType;

  //
  // the element type
  //
  type elemType;

  //
  // a reference to the local domain class for this array and locale
  //
  const locDom: LocBlock1DDom(idxType);

  //
  // the block of local array data
  //
  var myElems: [locDom.myBlock] elemType;

  //
  // the accessor for the local array -- assumes the index is local
  //
  def this(i: idxType) var {
    return myElems(i);
  }

  //
  // iterator over the elements owned by this locale
  //
  def these() var {
    for elem in myElems {
      yield elem;
    }
  }

  //
  // this is the parallel iterator for the local array, see global
  // domain parallel iterators for general notes on the approach
  //
  def newThese(param iterator: IteratorType)
        where iterator == IteratorType.leader {
  }

  def newThese(param iterator: IteratorType, followThis) var
        where iterator == IteratorType.follower {
  }

  //
  // prints out this locale's piece of the array
  //
  def writeThis(x: Writer) {
    // May want to do something like the following:
    //      on loc {
    // but it causes deadlock -- see writeThisUsingOn.chpl
    x.write(myElems);
  }

  //
  // query for the number of local array elements
  //
  def numElements {
    return myElems.numElements;
  }
}

// TODO: Have the global class leader/follower iterators defer to the
// local class leader/followers once we're within a locale?

// TODO: Make these into an official distribution?

config param debugBradsBlock1D = false;

// TODO: This would need to be moved somewhere more standard
enum IteratorType { leader, follower };

//
// The distribution class
//
class Block1DDist {
  //
  // The distribution's index type and domain's global index type
  //
  type idxType = int(64);

  //
  // The bounding box that defines the block distribution
  //
  const boundingBox: domain(1, idxType);

  //
  // a domain and array describing the set of target locales to which
  // the indices are mapped
  //
  const targetLocDom: domain(1);
  const targetLocs: [targetLocDom] locale;
  //
  // NOTE: originally I wrote this as:
  //
  //   const targetLocs = Locales;
  //   const targetLocDom = targetLocs.domain;
  //
  // but this had two interesting problems:
  //
  // (1) the capture of the targetLocs array only makes a copy of the
  //     array, not of its domain, so if someone were to resize the
  //     LocaleSpace domain outside of the class, this would inadvertantly
  //     get resized as well.  We really want to make a copy of both the
  //     domain and array (which I now do in the constructor).
  //
  // (2) Initializing targetLocs with Locales prevents us from assigning
  //     anything other than a numLocales-ary array of locales to it
  //     which is stricter than I wanted -- I only wanted to restrict
  //     us to a 1D array of locales.  In our current model, this would
  //     require us to have some sort of [domain(1)] locale declaration
  //     to make it work.  Or we could think about whether a model in
  //     which only the array's static type information is inferred
  //     for a field?

  //
  // an array of local distribution class descriptors -- set up in
  // initialize() below
  //
  // TODO: would like this to be const and initialize in-place,
  // removing the initialize method; would want to be able to use
  // an on-clause at the expression list to make this work.
  // Otherwise, would have to move the allocation into a function
  // just to get it at the statement level.
  //
  // WANTED:
  //
  /*
  const locDist: [loc in targetLocDom] LocBlock1DDist(idxType)
                   = on targetLocs(loc) do
                       new LocBlock1DDist(idxType, targetLocDom.order(loc), this);
  */
  //
  // but this doesn't work yet because an array forall initializer
  // apparently can't refer to a local member domain.
  //
  const locDist: [targetLocDom] LocBlock1DDist(idxType);
  //
  // WORKAROUND: Initialize in the constructor instead
  //

  def Block1DDist(type idxType = int(64), bbox: domain(1, idxType),
                  targetLocales: [?targetLocalesDomain] locale) {
    boundingBox = bbox;
    targetLocDom = targetLocalesDomain;
    targetLocs = targetLocales;
    //
    // WANT TO DO:
    /*
    for locid in targetLocDom do
      on targetLocs(locid) do
        locDist(locid) = new LocBlock1DDist(idxType, locid, this);
    */
    //
    // BUT results in a _heapAlloc(type int(64)) call.
    // WORKAROUND:
    helpConstruct();
  }
  //
  // WORKAROUND CONTINUED:
  //
  def helpConstruct() {
    for locid in targetLocDom do
      on targetLocs(locid) do
        locDist(locid) = new LocBlock1DDist(idxType, locid, this);
  }
  //
  // END WORKAROUND
  //

  def writeThis(x:Writer) {
    x.writeln("BradsBlock1DPar");
    x.writeln("---------------");
    x.writeln("distributes: ", boundingBox);
    x.writeln("across locales: ", targetLocs);
    x.writeln("indexed via: ", targetLocDom);
    x.writeln("resulting in: ");
    for locid in targetLocDom do
      x.writeln("  [", locid, "] ", locDist(locid));
  }

  //
  // Create a new domain over this distribution with the given index
  // set (inds) and global index type (idxType, idxType)
  //
  // TODO: What would we do if domIdxType did not match idxType?
  //
  def newDomain(inds, type domIdxType = idxType) where domIdxType == idxType {
    return new Block1DDom(idxType, this, inds);
  }

  //
  // compute what chunk of inds is owned by a given locale -- assumes
  // it's being called on the locale in question
  //
  def getChunk(inds, locid) {
    // use domain slicing to get the intersection between what the
    // locale owns and the domain's index set

    // TODO: Should this be able to be written as myChunk[inds] ???
    return locDist(locid).myChunk(inds.dim(1));
  }

  //
  // Determine which locale owns a particular index
  //
  def ind2locInd(ind: idxType) {
    const ind0 = ind - boundingBox.low;
    const loc0 = (ind0 * targetLocs.numElements) / boundingBox.numIndices;
    const locInd = loc0: index(targetLocs.domain) + targetLocs.domain.low;
    return locInd;
  }

  def ind2loc(ind: idxType) {
    return targetLocs(ind2locInd(ind));
  }
}

//
// A per-locale local distribution class
//
class LocBlock1DDist {
  //
  // The distribution's index type and domain's global index type
  //
  type idxType;

  //
  // This stores the piece of the global bounding box owned by
  // the locale.  Note that my original guess that we'd want
  // to use lclIdxType here is wrong since we're talking about
  // the section of the global index space owned by the locale.
  //
  const myChunk: domain(1, idxType);
  const locid: int;
  const loc: locale;

  //
  // Compute what chunk of index(1) is owned by the current locale
  // Arguments:
  //
  def LocBlock1DDist(type idxType,
                     _locid: int, // the locale index from the target domain
                     dist: Block1DDist(idxType) // reference to glob dist
                     ) {
    locid = _locid;
    loc = dist.targetLocs(locid);
    const lo = dist.boundingBox.low;
    const hi = dist.boundingBox.high;
    const numelems = hi - lo + 1;
    const numlocs = dist.targetLocDom.numIndices;
    const locid0 = dist.targetLocDom.order(locid); // 0-based locale ID
    const blo = if (locid0 == 0) then min(idxType)
                else procToData((numelems: real * locid0) / numlocs, lo);
    const bhi = if (locid0 == numlocs - 1) then max(idxType)
                else procToData((numelems: real * (locid0+1)) / numlocs, lo) - 1;
    myChunk = [blo..bhi];
    if debugBradsBlock1D then
      writeln("locale ", locid, " owns ", myChunk);
  }

  //
  // a helper function for mapping processors to indices
  //
  def procToData(x, lo)
    return (lo + (x: lo.type) + (x:real != x:int:real));

  def writeThis(x:Writer) {
    x.write("locale ", loc.id, " owns chunk: ", myChunk);
  }
}

//
// The global domain class
//
class Block1DDom {
  //
  // The index types of the domain
  //
  type idxType;

  //
  // a pointer to the parent distribution
  //
  const dist: Block1DDist(idxType);

  //
  // a domain describing the complete domain
  //
  const whole: domain(1, idxType);

  //
  // an array of local domain class descriptors -- set up in
  // initialize() below
  //
  //
  // TODO: would like this to be const and initialize in-place,
  // removing the initialize method; would want to be able to use
  // an on-clause at the expression list to make this work.
  // Otherwise, would have to move the allocation into a function
  // just to get it at the statement level.
  //
  var locDoms: [dist.targetLocDom] LocBlock1DDom(idxType);

  def initialize() {
    for locid in dist.targetLocDom do
      on dist.targetLocs(locid) do
        locDoms(locid) = new LocBlock1DDom(idxType, this,
                                           dist.getChunk(whole, locid));
    if debugBradsBlock1D then
      [loc in dist.targetLocDom] writeln(loc, " owns ", locDoms(loc));
  }

  //
  // the iterator for the domain -- currently sequential
  //
  def these() {
    for blk in locDoms do
      // TODO: Would want to do something like:
      // on blk do
      // But can't currently have yields in on clauses
        for ind in blk do
          yield ind;
  }

  //
  // this is the parallel iterator for the global domain, following
  // a variation on Steve and David's proposals -- I've split the
  // single iterator into two iterators, distinguished by where
  // clauses on their parameter values.  This permits each to only
  // take the parameters it cares about; permits the leader to be
  // defined in an inlineable way; and permits the follower for an
  // array iterator to be a var iterator
  //
  // I've named these methods newThese() for the time being
  // to avoid conflicting with the above which is currently targeted
  // by the compiler.  My current assumption is that we would want to
  // overload these() to serve this purpose in the final language
  // definition.
  //
  def newThese(param iterator: IteratorType)
        where iterator == IteratorType.leader {
    //
    // TODO: This currently only results in a single level of
    // per-locale parallelism -- no per-core parallelism; maybe
    // approach this by deferring to the local leader/follower
    // iterators at some point?
    //
    // TODO: Really want the parallelism across the target locales
    // to be expressed more independently of the distribution by
    // pushing it into the leader iterator.  Need to get an on clause
    // into here somehow.  That is:
    //
    //   coforall locDom in locDoms do
    //     on locDom do
    //       yield locDom.myBlock - whole.low;
    //
    // TODO: And really want to split the inter- and intra-locale
    // parallelism into two separate stages for communication
    // optimization and the like
    //
    // TODO: Abstract this subtraction of low into a function?
    // Note relationship between this operation and the
    // order/position functions -- any chance for creating similar
    // support? (esp. given how frequent this seems likely to be?)
    //
    for locDom in locDoms do
      yield locDom.myBlock - whole.low;
  }

  def newThese(param iterator: IteratorType, followThis)
        where iterator == IteratorType.follower {
    //
    // TODO: Abstract this addition of low into a function?
    // Note relationship between this operation and the
    // order/position functions -- any chance for creating similar
    // support? (esp. given how frequent this seems likely to be?)
    //
    // TODO: Is there some clever way to invoke the leader/follower
    // iterator on the local blocks in here such that the per-core
    // parallelism is expressed at that level?  Seems like a nice
    // natural composition and might help with my fears about how
    // stencil communication will be done on a per-locale basis.
    for i in followThis {
      yield i + whole.low;
    }
  }

  //
  // the print method for the domain
  //
  def writeThis(x:Writer) {
    x.write(whole);
  }

  //
  // how to allocate a new array over this domain
  //
  def newArray(type elemType) {
    return new Block1DArr(idxType, elemType, this);
  }

  //
  // queries for the number of indices, low, and high bounds
  //
  def numIndices {
    return whole.numIndices;
  }

  def low {
    return whole.low;
  }

  def high {
    return whole.high;
  }
}

//
// the local domain class
//
class LocBlock1DDom {
  //
  // The index type of the domain
  //
  type idxType;

  //
  // a reference to the parent global domain class
  //
  const wholeDom: Block1DDom(idxType);

  //
  // a local domain describing the indices owned by this locale
  //
  var myBlock: domain(1, idxType);

  //
  // iterator over this locale's indices
  //
  def these() {
    // May want to do something like:
    // on this do
    // But can't currently have yields in on clauses
    for ind in myBlock do
      yield ind;
  }

  //
  // this is the parallel iterator for the local domain, see global
  // domain parallel iterators for general notes on the approach
  //
  def newThese(param iterator: IteratorType)
        where iterator == IteratorType.leader {
  }

  def newThese(param iterator: IteratorType, followThis)
        where iterator == IteratorType.follower {
  }

  //
  // how to write out this locale's indices
  //
  def writeThis(x:Writer) {
    x.write(myBlock);
  }

  //
  // queries for this locale's number of indices, low, and high bounds
  //
  def numIndices {
    return myBlock.numIndices;
  }

  def low {
    return myBlock.low;
  }

  def high {
    return myBlock.high;
  }
}

//
// the global array class
//
class Block1DArr {
  //
  // The index type of the domain
  //
  type idxType;

  //
  // the array's element type
  //
  type elemType;

  //
  // the global domain descriptor for this array
  //
  var dom: Block1DDom(idxType);

  //
  // an array of local array classes
  //
  // TODO: would like this to be const and initialize in-place,
  // removing the initialize method; would want to be able to use
  // an on-clause at the expression list to make this work.
  // Otherwise, would have to move the allocation into a function
  // just to get it at the statement level.
  //
  var locArr: [dom.dist.targetLocDom] LocBlock1DArr(idxType, elemType);

  def initialize() {
    for locid in dom.dist.targetLocDom do
      on dom.dist.targetLocs(locid) do
        locArr(locid) = new LocBlock1DArr(idxType, elemType, dom.locDoms(locid));
  }

  //
  // the global accessor for the array
  //
  def this(i: idxType) var {
    return locArr(dom.dist.ind2locInd(i))(i);
  }

  //
  // the iterator over the array's elements, currently sequential
  //
  def these() var {
    for loc in dom.dist.targetLocDom {
      // TODO: May want to do something like:
      // on this do
      // But can't currently have yields in on clauses
      for elem in locArr(loc) {
        yield elem;
      }
    }
  }

  //
  // this is the parallel iterator for the global array, see th
  // example for general notes on the approach
  //

  def newThese(param iterator: IteratorType)
        where iterator == IteratorType.leader {
    for blk in dom.newThese(IteratorType.leader) do
      yield blk;
  }

  def newThese(param iterator: IteratorType, followThis) var
        where iterator == IteratorType.follower {
    for i in followThis {
      yield this(i + dom.low);
    }
  }

  //
  // how to print out the whole array, sequentially
  //
  def writeThis(x: Writer) {
    var first = true;
    for loc in dom.dist.targetLocDom {
      // May want to do something like the following:
      //      on loc {
      // but it causes deadlock -- see writeThisUsingOn.chpl
        if (locArr(loc).numElements >= 1) {
          if (first) {
            first = false;
          } else {
            x.write(" ");
          }
          x.write(locArr(loc));
        }
        //    }
      stdout.flush();
    }
  }

  //
  // a query for the number of elements in the array
  //
  def numElements {
    return dom.numIndices;
  }
}

//
// the local array class
//
class LocBlock1DArr {
  //
  // The index type of the domain
  //
  type idxType;

  //
  // the element type
  //
  type elemType;

  //
  // a reference to the local domain class for this array and locale
  //
  const locDom: LocBlock1DDom(idxType);

  //
  // the block of local array data
  //
  var myElems: [locDom.myBlock] elemType;

  //
  // the accessor for the local array -- assumes the index is local
  //
  def this(i: idxType) var {
    return myElems(i);
  }

  //
  // iterator over the elements owned by this locale
  //
  def these() var {
    for elem in myElems {
      yield elem;
    }
  }

  //
  // this is the parallel iterator for the local array, see global
  // domain parallel iterators for general notes on the approach
  //
  def newThese(param iterator: IteratorType)
        where iterator == IteratorType.leader {
  }

  def newThese(param iterator: IteratorType, followThis)
        where iterator == IteratorType.follower {
  }

  //
  // prints out this locale's piece of the array
  //
  def writeThis(x: Writer) {
    // May want to do something like the following:
    //      on loc {
    // but it causes deadlock -- see writeThisUsingOn.chpl
    x.write(myElems);
  }

  //
  // query for the number of local array elements
  //
  def numElements {
    return myElems.numElements;
  }
}