-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Added TypeCheckTypeExp() and changed function type literal and similar type-checking logic to use the new function #1256
Conversation
…n parameter and return type before calling InterpExp() on them
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'm not clear that this is the right fix: if InterpExp needs to always type-check the expression first, shouldn't type_checker have a wrapper for InterpExp that does that, rather than expecting each place that calls InterpExp to typecheck explicitly?
As an example, TupleValue seems to call InterpExp without calling TypeCheckExp, maybe that could have this same bug? It feels like a central solution that addresses all these cases equally may be safer. |
For this patch, I temporarily added a (void)e.static_type() call to InterExp() and InterpPattern() to verify there were no more crashes surfaced by existing tests (and can add a permanent check based on CheckHasStaticType() Geoff suggested as a follow-up). I agree a wrapper might be good, but some places like the logic for FieldAccessExpression (around line 744 in type_checker.cpp) sometimes only calls TypeCheckExp() and not InterpExp() depending on expression type, so the wrapper won't be used 'pervasively' -- if that sounds good I can change 'obvious' TypeCheck+Interp' sequences to use a wrapper. |
I'm pretty suspicious of anything that type-checks and then immediately evaluates an expression -- I would expect there to be a step in between that checks that the type of the expression is what we were expecting and, if not, attempts implicit conversion to that type. Notionally what this function type handling code should be doing is type-checking the expression, then implicitly converting it to type It might be premature to factor out a wrapper before those conversions are in place; we might find the call sites end up a bit less uniform once that's done. (Or we might not, I'm not sure.) |
@zygoloid There's a thread on #explorer, if you want to disagree can you take it up there so we're discussing in one place? |
After discussion with @jonmeow I think it would be reasonable to factor out a function for type-checking expressions that are expected to produce types. For example, a function
(And at some later point we can add an implicit conversion to the Looking through the calls to
|
Would it be ok to merge the current PR as is to fix the immediate crashing bug, and do the suggested refactoring/improvement changes as a follow-up (as these changes are less trivial now)? |
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 ok to merge the current PR as is to fix the immediate crashing bug, and do the suggested refactoring/improvement changes as a follow-up (as these changes are less trivial now)?
Either way works for me; I'll leave this for @jonmeow to decide.
I'd rather it be done here -- let me know if you need more explanation on why, but @pk19604014 I think that VariableDeclaration should probably be verifying what InterpExp is returning, and @zygoloid's suggestion is both consistent with my earlier request and would help make that VariableDeclaration difference more obvious. The present state feels like an incomplete fix to me, which while it may stop crashing, doesn't feel like the right outcome. Also, the change to a helper function still feels quite trivial to me. |
…into fuzz_231844390
I like the suggestion of @zygoloid regarding creating a helper function for type expressions ( |
Ok done PTAL |
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/impl/fail_impl_as_parameterized.carbon:[[@LINE+1]]: expected constraint after `as`, found value of type String | ||
external impl i32 as String {} |
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.
This test was testing the case where the thing after as
is the name of a parameterized interface that's missing its parameters. I think we still want to test that case explicitly, even if it covers the same code paths as this case right now; can we add this file as a new test and keep the existing test as-is?
auto value, InterpExp(&arg.expression(), arena_, trace_stream_)); | ||
CARBON_RETURN_IF_ERROR( | ||
ExpectIsConcreteType(arg.expression().source_loc(), value)); | ||
CARBON_RETURN_IF_ERROR(TypeCheckTypeExp(&arg.expression(), impl_scope)); |
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 think that these cases that are ignoring the return value shouldn't be interpreting the type expression at all. This will result in quadratic runtime for a case such as {.a: {.a: {.a: ...}}}
because each level of struct type will repeat the evaluation of the inner struct literal. I've verified the runtime of this grows superlinearly in practice:
- ~45ms for 50 levels of nesting
- ~80ms for 100 levels of nesting
- ~200ms for 200 levels of nesting
- ~680ms for 400 levels of nesting
I guess this is not really fixable until we switch away from ExpectIsType
to implicitly converting to Type
, though, so let's not block this patch on a fix for that.
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.
Looks good to me with the requested test fix.
Merging now; I'll make the requested test fix myself as a separate PR. |
This change updated a test to use a different example to make sure a diagnostic was still being exercised, but as a consequence lost test coverage of the situation the test was originally intended to cover. Add back the old test and put the new test into a different file.
…r type-checking logic to use the new function (#1256)
This change updated a test to use a different example to make sure a diagnostic was still being exercised, but as a consequence lost test coverage of the situation the test was originally intended to cover. Add back the old test and put the new test into a different file.
Fixes #1249