Issue 1:
For robustness of error messages, we should ensure all code paths where we throw an ErrorReport are tested and return meaningful errors.

As of today, this is the coverage of the times that we throw ErrorReport for a run of test_jit.py. Format is line, #calls, source code:

torch/csrc/jit/script/compiler.cpp:
148| 0| throw ErrorReport(loc) << "cannot re-assign '" << name << "' to a value of type " << value->kind()
153| 0| throw ErrorReport(loc) << "cannot re-assign '" << name << "' because it has type " << value->kind()
157| 2| throw ErrorReport(loc) << "variable '" << name << "' previously has type " << simple_parent->type()->name()
192| 4| throw ErrorReport(range) << "undefined value " << ident;
248| 0| throw ErrorReport(loc) << "attributes must be scalars or lists of scalars";
252| 0| throw ErrorReport(loc) << "attributes must be constant expressions";
497| 0| throw ErrorReport(loc) << "argument 'chunks' must be a constant";
549| 0| throw ErrorReport(loc) << "unknown builtin op";
551| 9| throw ErrorReport(loc) << "arguments for call are not valid:\n"
565| 0| throw ErrorReport(range) << "expected a tensor value but found a tuple";
616| 0| throw ErrorReport(def.params().range()) << "methods must have a self argument";
713| 0| throw ErrorReport(stmt) << "return statements can appear only at the end "
913| 0| throw ErrorReport(range)
926| 0| throw ErrorReport(stmt)
930| 0| throw ErrorReport(stmt) << "Iteration variable unpacking is not supported";
934| 0| throw ErrorReport(targets[0]) << "Starred unpacking is currently not"
992| 0| throw ErrorReport(assignee)
998| 0| throw ErrorReport(r)
1003| 0| throw ErrorReport(r) << "A Starred expression may only appear on the "
1015| 0| throw ErrorReport(stmt)
1042| 3| throw ErrorReport(stmt)
1048| 4| throw ErrorReport(stmt)
1060| 0| throw ErrorReport(var) << "Cannot pack a tuple into a non-variable.";
1169| 0| throw ErrorReport(ident) << "print doesn't accept any keyword arguments";
1249| 0| throw ErrorReport(tree) << "Unexpected starred expansion. File a bug report.";
1284| 0| throw ErrorReport(tree) << "NYI: " << tree;
1305| 0| throw ErrorReport(input) << "Unrecognized type: " << type;
1364| 0| throw ErrorReport(loc)
1461| 0| throw ErrorReport(def) << "duplicate definition of function '" << name << "'";
1495| 4| throw ErrorReport(loc) << value->type()->name() << " cannot be used as a tuple";
1500| 0| throw ErrorReport(loc) << "expected " << expected << " " << what << " but found " << actual;
torch/csrc/jit/script/compiler.h:
41| 0| throw ErrorReport(loc) << kind() << " cannot be used as a value";
46| 0| throw ErrorReport(loc) << "attribute lookup is not defined on " << kind();
52| 0| throw ErrorReport(loc) << kind() << " cannot be used as a tuple";
78| 0| throw ErrorReport(loc) << "cannot call a " << kind();
torch/csrc/jit/script/init.cpp:
56| 3| throw ErrorReport(loc) << "calling a Python function with an incorrect number "
61| 1| throw ErrorReport(loc) << "type mismatch at argument " << i << ": expected "
70| 0| throw ErrorReport(loc) << "keyword arguments in Python calls aren't supported";
103| 0| throw ErrorReport(loc) << "Python functions can currently only return Tensors";
134| 0| throw ErrorReport(loc) << "object has no attribute " << name;
210| 0| throw ErrorReport(loc) << "unsupported attribute lookup on " << py::repr(self) << ".";
276| 2| throw ErrorReport(loc) << "attribute '" << field << "' of type '" << typeString(attr) << "' is not usable in a script method (did you forget to add it __constants__?)";
279| 0| throw ErrorReport(loc) << "module has no attribute '" << field << "'";
torch/csrc/jit/script/module.cpp:
34| 1| throw ErrorReport(loc) << " method '" << callee.name()
44| 0| throw ErrorReport(loc) << failure_messages.str();
torch/csrc/jit/script/tree_views.h:
169| 0| throw ErrorReport(tree) << "Maybe trees can have at most one subtree";
211| 0| throw ErrorReport(tree) << kindToString(tree->kind()) << " is not a valid Type";
228| 0| throw ErrorReport(tree) << kindToString(tree->kind()) << " is not a valid Stmt";
266| 0| throw ErrorReport(tree) << kindToString(tree->kind()) << " is not a valid Expr";
333| 0| throw ErrorReport(tree) << kindToString(tree->kind()) << " is not a valid ScalarType";
451| 0| throw ErrorReport(tree) << "is not a valid AssignKind";
525| 0| throw ErrorReport(tree) << "BinOp expected 2 subtrees, found " << tree->trees().size();
528| 0| throw ErrorReport(tree) << kindToString(tree->kind()) << " is not a valid BinOp";
548| 0| throw ErrorReport(tree) << "UnaryOp expected 1 subtree, found " << tree->trees().size();
551| 0| throw ErrorReport(tree) << kindToString(tree->kind()) << " is not a valid UnaryOp";

Issue 2:
In DataParallel, gradients from GPUs are summed to update parameters. This design results in the subtlety that training convergence depends on the number of GPUs you used to train, which makes experiments less duplicable and trackable when the number of gpus is different in hardware systems or when it is controlled by augment like --gpus 0,1. Is it better to average gradients from all GPUs like torch.nn.parallel.DistributedDataParallel does, so that the training convergence is independent on the number of gpus? Thanks!