This summer I worked with Professor Zachary Palmer of the Computer Science Department in the field of error resugaring. Specifically, I worked on helping to generate helpful error messages when a user writes a new language with special features on top of an existing language. For example, let's say there's an existing language that can take numbers and add or subtract them, but that's all it can do, and a user wants to use that language to write a language that is capable of both adding and multiplying/dividing. And then they get that language running, but when another user comes along and writes code in that program that says, "Tell me what 5/0 is", that then gets translated into the lower-level language saying "Tell me what one-zeroeth of 5 is", and so the lower-level language complains, "There is no such thing as one-zeroeth". Existing layered languages would probably just return this error message, which might confuse the user, because they never directly mentioned one-zeroeth. So our goal is to find a way to translate that back to clearly say to the user, "You can't divide by zero", and save them the confusion.
Our solution to this problem was to ID every piece of information (every variable, every value, every expression, etc.) and then, if they had to be simplified during the translation process down into the simpler language, we would make a note about which piece of information that was, using the ID, and what that transformation process was, and save any bit of extra information that was lost. Then, after the errors had been generated, as we were translating the errors back into something more complex, we would check each piece of information's ID in our "notepad" and see if it had any notes about it. If it did, then we could use the rest of what that entry contained, specifically the lost information itself, and create a fully-informed error message suited to the type of structure that that structure originally was when the user wrote it.