Parameters are pushed onto a heterogenous stack.
The idea of parameter lists was borne out of:
The idea of exceptions was borne out of:
Return values are placed on the stack.
The idea of return values was borne out of:
The compiler must do extra work:
A stack is an optimization of list.
A list is a collection.
The concept of stack conflates several issues:
Every type might be stored in a separate collection.
The parameters to a routine might be a collection of typed collections.
Assertion: if something is in a typed collection, the it has the correct type.
Type check is done at "push" time (where "push" means to add the item to its collection).
What can we do if two parameters have the same type?
One solution - allow type synonyms.
Each parameter gets a unique name, but the name is synonymed to be of a given type.
fn(a : int, b : int)
a = int
b = int
I have implemented a version of the above ideas and will document the operations (about 5) that I use (push-and-check-type, pop, list-add, etc.)
The PT Pascal compiler, written in the language S/SL, used stacks for scoping and type checking. The PT Pascal source code and S/SL source code can be found at https://research.cs.queensu.ca/home/cordy/pub/downloads/ssl/.
A version of S/SL with input and output parameters was documented in a thesis - I can't find my copy of the thesis nor can I remember the author's name.
 Parameters of all types share the same stack.