-
Notifications
You must be signed in to change notification settings - Fork 803
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
Give nice explanation when else case is missing #1142
Conversation
Do we need to keep the original (confusing) unit / string error message? |
we can easily replace the whole message. Can you come up with something nice? |
Also, I'm thinking this message shouldn't occur with if foo then
1 In this case we should somehow mention about returning unit too. |
I find the last sentence in the error message confusing. There is only one case, so "All cases" is correct but maybe not easy to understand. When the else-branch is omitted the type of the then-branch must be unit. Maybe this works instead "If / then is an expression in F#, the then branch it must be of type unit." |
Also we shouldn't mention |
@forki - just get rid of the first bit :-)
This is exactly where this error message should live - someone wants to return 1 but needs a default value for the else branch. The original idea is that the user wants to a return a value e.g. integer in this case. So they need to return a value on the "else" branch as well, rather than using ignore and turning it into a statement. |
Seems there is no tests that checks error message for missing else branch yet. |
@dsyme does it make sense to give a different error code in this case? |
Sorry for confusion, I meant my code outside of a |
@smoothdeveloper can you create a specific case and tell me what you want to improve? |
For #1105 we now have: |
let a = true
if a then
1
I think in this case (we don't assign the expression to anything) we should keep this current message (or find a better one) instead of talking about else. The user probably did a mistake with the last statement in the |
@smoothdeveloper as far as I can see we don't have the left hand side available at this point. So we would need to make the error message cover both cases. |
@dsyme I'm not sure if it's a good idea to extend the TcEnv, but somehow I need to pass context information down to the deeper levels of the type checker and to the constraint solver. I assume if we implement more of these messages this additional information will generalize a bit. But I'm happy to use whatever techniques you prefer to get this one done. |
So tests are green. This is ready for first review |
@isaacabraham So the assumption is that it's a forgotten |
Yeah there are like a million more things that are possible. We can't respond to everything, but I think with this assumption (and without changing too much) we can at least help newcomers to overcome one of the main issues. |
70afc9d
to
90be111
Compare
eModuleOrNamespaceTypeAccumulator: ModuleOrNamespaceType ref | ||
|
||
/// Error Message for type errors | ||
specializedErrorMessage : ((string*string) -> string) option |
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.
Extending TcEnv is a bit problematic. for two reasons
- We really need to be reducing the size of TcEnv instead of increasing it. One technique would be to split it between hot (varying fields) and cold (usually empty/None/...) fields, and only allocate the cold block when one of the fields gets a non-default value.
- The entry you've added needs to be reset to "None" at an appropriate point. For example, when you go into a lambda, or perhaps any expression that's not a control construct i.e. not an if/then/else, match, try/with, try/finally.
Adding a function also feels a bit wrong - I'd rather have a more explicit representation of the information being added here, so we know more clearly when the information no longer applies (e.g. in the cases mentioned above), or we can work out how it interacts with other "expression context" information we are bound to add in the future. So it feels right to change this to be a "eContextInfo" field that contains a union between various expression contexts, with a clear definition in the ///
comments for the cases as to what it means to be in that context. The two contexts added for this PR would presumably be ElseBranch
and IfBranchWithoutElse
13e8b69
to
ea8f0f2
Compare
Personally I actually wouldn't refer to unit in the message - in any case, you wouldn't see this message in the case that you had a single branch that returned unit anyway. What I originally was hoping was getting across that if / then / else is an expression which has some tangible result, and therefore the return type of all branches must be unified - hence the original (somewhat verbose) explanation. You wouldn't believe how many people just assume that if / then / else is a statement in every language. How about this?
|
@isaacabraham I can believe that :) Perhaps this (taking @KevinRansom and @isaacabraham suggestions together):
|
|
@KevinRansom I've said my piece. I think adding "ignore" is just going to confuse people and doesn't relate to 99.9999% of the times that this error will show up. |
If expression needs an else expression if the return type differs from unit Something like that would have helped me |
@KevinRansom Yes, no need to mention "ignore", it's almost certainly not the right action for the user to take. For example, consider
The problem here is that the function has not been applied to all its arguments and adding "ignore" will be incorrect. My current suggestion:
I've tried a few times and it's very hard to also explain that if the 'then' branch has type 'unit' then the 'else' branch can be omitted. Here's my best attempt - @isaacabraham what do you think?
thanks |
@dsyme I think your suggestion above (2 days ago) was very good and would be my preference. |
Going with:
|
Thank you for taking care of this. |
One more suggestion. Trying to put it as simply as possible.
|
why not go all in?
or something ;-) |
Implements #1104 and #1105
For the following code
we had the following error:
Now it's:
For #1105 we now have: