-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enhanced errors #874
base: development
Are you sure you want to change the base?
Enhanced errors #874
Conversation
- Only shows the new error on NonAssignableLHSError - Only displays the first line of the errored code, if the expression/etc is segmented on multiple lines it will for now not show the entire part
Extracted the printer to own file so that TypeError only holds the data structures and text for different error descriptions/suggestions. Also removed all deprecated code.
This is due to the visual bugs in prettyprinter.hs introduced by the differences on how the libraries handle empty documents as well as differences with functions such as nest and hang.
Need to expose the annotated version of Doc in prettyprinter to apply prettyprinted text in suggestions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like this PR. The code is quite understandable and reading the error messages is much much better than what we had in place before. I have added refactorings, suggestions and spotted a few places that I think need a bit of a clarification, before we merge this.
One thing that I do not know if it is too difficult, would be to basically compile an Encore program with the explanation flag and, if there are any errors, show not only the place and backtrace of the error, but also the suggestion that matches the appropriate code. This way, if I get an error, I do not have to chase the error / warning code to get the good explanation.
As I said, really good PR. Looking forward to the changes :)
showPosition :: Position -> Doc TCStyle | ||
showPosition pos = styleLogistic (text "-->") <+> (text $ show $ pos) | ||
|
||
codeViewer_ver1 :: (TCType a, Suggestable a) => a -> [String] -> Doc TCStyle |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
which of the codeViewers is the right one?
|
||
pipe = char '|' | ||
|
||
declareError :: Error -> Doc TCStyle |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The declareError
and declareWarning
are pretty much the same except for the hash format and the word "Error" or "Warning". This fact make it good for a refactoring. I would recommend:
- Create in
ExplainTable.hs
the following class and instances and remove the methodslookupHash
andlookupHashW
:class Explanainable a where explain :: a -> Maybe Int instance Explanainable Error where explain err = toKey err instance Explanainable Warning where explain warn = toKeyW warn
This basically allows you to have ad-hoc polymorphism over the types, which is what you want. We want to be able to call the method explain
without having to call one specific method for errors and another one for warnings.
- Update the functions
declareError
anddeclareWarning
to the following ones:
declareError :: Error -> Doc TCStyle
declareError = printText "[E%04d]" "Error" . explain
declareWarning :: Warning -> Doc TCStyle
declareWarning = printText "[W%04d]" "Warning" . explain
printText _ _ Nothing = empty
printText format msg (Just num) = let hash = text $ printf format num
in styleClassify $ text msg <> hash <> char ':'
In my personal opinion, this is more understandable than the function before and it hides internal facts that are not needed for the functions declareWarning
and declareError
, such as that there is an option type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
I like it! it has been changed.
-
This solution would not produce the correct result. it need to do:
styleClassify $ text msg ______ <> char ':'
Regardless of the Maybe-type. And I like to preserve not having two lines that has to be the same. I have reformatted the function a little hoping to convey that more properly.
src/front/TopLevel.hs
Outdated
@@ -14,6 +14,9 @@ import System.Directory | |||
import System.IO | |||
import System.Exit | |||
import System.Process | |||
import System.Posix.Process |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would it be possible to import only the things that you are using?
Unless you really require a lot of functions from the modules imported here.
Basically, I do not know what combinator from System.Posix.Process
, System.Pager
, System.Console.ANSI
you are using.
makeNotation :: Doc TCStyle | ||
makeNotation = styleLogistic (pipe $+$ equals) <+> styleDesc (text "note:") | ||
|
||
-- How to determine if to use a smallSuggest or longSuggest: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it seems that we can choose between small and long suggestions, can we choose one version from the version1 or version2 and change the small or long suggestions as we see fit? Maybe adding some documentation at the beginning of the module can clear things up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could definitely add some documentation.
What do you mean version1 or version2? the codeviewer?
There are two versions right now doing the same thing, one is ment to be removed and amended before merging.
It's made so that you could construct different codeviewers and choose based on the error
(an example is if you have the wrong arguments for a function, the code viewer could display the actual function declaration as well as where the programmer wrote wrong. I think the declaration s range also includes the entire body which is why I never made such a viewer)
The small and long suggest will always print, which is why default is empty (nothing will print).
A desire that I included as future work was to refactor the suggestions to be returned as one function, meaning that you could evaluate the code, and depending on how much information you want to relay back you could then choose if it would be displayed as a short or long suggest (or both). Right now you would need to compute this for both functions individually.
|
||
|
||
printError :: TCError -> IO () | ||
printError err@(TCError _ Env{bt = []}) = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the TCError
ADT was updated from TCError Error Backtrace
to TCError Error Env
. However, I believe that you never make use of the environment when you try to print an error. I was wondering if you really need the environment in the TCError
. I am sure I am wrong, but I could not find where do you make use of the Env
from the TCError
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Env
is passed along to the long and short suggest. Otherwise we could not evaluate an error and give suggestions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right! I just saw that you need the environment for a specific case of the long suggest. The short suggest doesn't seem to use it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
short suggest uses it as well to figure out if the name of an unknown method is available as a function. (As I would like to refactor this code into a single function returning both the possible short and long suggestions it would be wise to leave the arguments the same)
| isMethodNameAFunction name ty env = text $ printf "Did you mean function `%s`?" (show name) | ||
smallSuggest _ = empty | ||
|
||
longSuggest (TCError (TypeMismatchError actual expected) _) = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the first two cases of longSuggest can be refactored using guards. They are an identical copy except from the error type/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a TypeWithCapabilityMismatchError has a very "ugly" description I think it might be more wise to remove it entirely from suggestible as a way of subtly informing that this error needs rework.
|
||
|
||
|
||
isMethodNameAFunction name ty env = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest to put this method inside a where
clause in the place where it is used, since it does not seem to be a combinator that is needed for multiple functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted these abstracted helper-functions to not be local so that it could be used by anything, specially as long as short and long-suggest are two different functions.
A desire that I included as future work was to refactor the suggestions to be returned as one function [...] Right now you would need to compute this for both functions individually.
Before merging, I would like to see if the other comments are addressed (or there is a reply). |
This pull request overhauls the visual style of encores error handling with the following functionalities:
Error output and structure
The ANSI escape sequences are removed it it does not detect a terminal as output, meaning if the output is redirected to a file or to a pipe, it will remove the color sequences and so that the output will remain clean.
Error explanations
If an error occurs that have an explanation it will display a hash-value in which you can provide to the compiler for further information.
$ encorec --explain E002
This will open up a pager with the text explaining a general case where this kind of error can occur.
Code analyzing
In the image we can see an inlined notation by the highlighted error and a longer note underneath. These notation can contain small information on what it expected and what you might wanted to do.
Suggestions available and small list of potential suggestions:
Limitations / TODOs
Range error
Due to the way the parser consumes whitespaces before determine end of token, there is a visual bug were the range of each token is the length of the token plus all spaces until the next token.
Inefficient Suggest analyzation
The result for the inlined suggestion as well as the longer underneath are handled by two separate functions, making it not possible to take advantage of the ability of determining after the fact what kind of message should be displayed where, if these were produced as one function it would be more efficient to not needing to re-evaluate values as well as determining the position based on the size or complexity of the result.