-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
Fix empty code blocks when trait used interface method #275
Conversation
I'm now struggling to get a mental model of how all this should work. I'm going to talk out loud here to see if I can make sense of it. We have a DAG of And there's the namespace for the current module. We use callpaths like Operations like A local implementation of a trait will go into the current namespace, into a special collection of trait implementations. If we try to use Now that I've typed this out it makes sense to me. While I was looking at the code it didn't. @sezna is what I've outlined above correct? |
OK, what I think is actually happening, as of the tip of this branch, is we have This isn't what I described above, where I suggested a local implementation goes into the local namespace. I experimented with a change, which instead did insert the implementation locally, and looked it up locally and it fixed the problem with the I think this is the core of the issue, and is essentially what I was trying to fix in #266. Typically we want implementations of traits to exist where they're declared, rather than pollute the namespace where the trait is declared. (I think?) But the standard types essentially are local (to everywhere) and so looking up their methods is special. This is kinda the crux of #187 in the first place. Damn, reading #187 again is essentially describing the problem we still have. How to have local trait implementations for local types but still to find the methods for standard types? Perhaps the solution is actually to put all the standard types into a namespace? |
We now insert trait implementations into the namespace where they're declared, rather than where the trait is declared. This involves using a full callpath to the trait as the key for the trait lookup hashmap. We therefore also lookup trait implementations in the local namespace to resolve them. Unfortunately this breaks trait implementations for standard types, like those found in `std::ops` for `std::ops::Ord` because without a fully qualified path to the types we will look for their trait implementations locally and not find them. A hack has been added to the lookup function which will first try the local namespace and then if unsuccessful try the module where the trait is declared. This works for all our current tests, but is fragile and it's bad to assume that we'll always find implementations for standard types where the trait is declared.
48e3275
to
cd9811c
Compare
I've pushed a commit with the change mentioned above, which breaks for It passes all the tests now, but if there's a better way to do this then we should work it out. |
I'm going to say this is good for now (if we have more pains later, we can revisit this, not a high priority), because I can't think of an example outside of implementations for primitive types where the types would not be in scope for either the trait or the place it is implemented. |
* Fix empty code blocks when trait used interface method * remove unused imports * Change the way trait implementations are handled by the namespace. We now insert trait implementations into the namespace where they're declared, rather than where the trait is declared. This involves using a full callpath to the trait as the key for the trait lookup hashmap. We therefore also lookup trait implementations in the local namespace to resolve them. Unfortunately this breaks trait implementations for standard types, like those found in `std::ops` for `std::ops::Ord` because without a fully qualified path to the types we will look for their trait implementations locally and not find them. A hack has been added to the lookup function which will first try the local namespace and then if unsuccessful try the module where the trait is declared. This works for all our current tests, but is fragile and it's bad to assume that we'll always find implementations for standard types where the trait is declared. Co-authored-by: Alexander Hansen <alexanderhansen@Alexanders-MacBook-Pro.local> Co-authored-by: Toby Hutton <toby@grusly.com>
Closes #241
Consider a trait declaration:
In order for
some_method
to type check its call tosome_interface_fn
, we need to insertsome_interface_fn
into the namespace before we actually have a function body for it. I usedto_dummy_func()
, which would take a typed trait function and insert it with an empty body. In the original design, this didn't matter because it was thrown away before code generation.Since then, we have added a copy of function declarations inside of function applications for ease of code generation. This was capturing the empty code block and keeping it around until code generation, causing weird bugs. This change throws away any dummy functions and makes trait declarations store
FunctionDeclaration
s instead ofTypedFunctionDeclaration
s, forcing a (correct) type-check when a trait is implemented and those function bodies actually exist.This change also removes
where
clauses for now, since their implementation relied on a faulty usage ofto_dummy_func
. Those will have to be implemented as a part of #272