-
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
Implement hierarchical trait map and namespace lookups. #6516
base: master
Are you sure you want to change the base?
Conversation
dc00260
to
60db3a9
Compare
60db3a9
to
486df45
Compare
CodSpeed Performance ReportMerging #6516 will not alter performanceComparing Summary
|
self.get_items_for_type(engines, type_id) | ||
.into_iter() | ||
.filter_map(|item| match item { | ||
ResolvedTraitImplItem::Parsed(_) => todo!(), |
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.
nit: I see that this was just moved from another file, but I think we should replace the todo!
with something else, like None
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.
nit: I see that this was just moved from another file, but I think we should replace the
todo!
with something else, likeNone
I don't think it should return None
in this case because that would be a silent failure to the dev. I think maybe an unreachable
here probably makes the most sense, and this code is not really designed to be called for parsed declarations.
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.
Overall it looks good, but I think there's a common pattern that can be abstracted out, and there's a nagging feeling at the back of my mind that you've introduced a shadowing issue. Let me know what you think - I might just be overthinking things.
let mut all_impld_traits: BTreeSet<(Ident, TypeId)> = Default::default(); | ||
while let Some(lexical_scope) = lexical_scope_opt { | ||
all_impld_traits.extend( | ||
lexical_scope | ||
.items | ||
.implemented_traits | ||
.get_implemented_traits(type_id, engines), | ||
); |
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.
Isn't there a shadowing issue here? Something like if a type implements two different traits with the same name but in different scopes, and then we refer to the type using the trait name.
My Rust skills aren't quite good enough to come up with a counter-example, but if there is a shadowing issue then it won't show itself until you eliminate the cloning of trait maps anyway.
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.
Isn't there a shadowing issue here? Something like if a type implements two different traits with the same name but in different scopes, and then we refer to the type using the trait name.
My Rust skills aren't quite good enough to come up with a counter-example, but if there is a shadowing issue then it won't show itself until you eliminate the cloning of trait maps anyway.
I think there should be no shadowing issue since the return is a list of traits, I asked @esdrubal for confirmation and he thinks at most we can get an ambuiguity error due to more traits being returned, which is what should happen I think.
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 suppose my question really is: Is there a case where this algorithm will throw an ambiguity error, but where shadowing actually resolves the ambiguity? I'm not sure, because I'm not sure a trait implementation can shadow another trait implementation.
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.
TraitMap::insert
is the method responsible for checking that we don't shadow other trait implementations.
TraitMap::insert
can insert more methods for impl selfs and should throw an error when methods with the same name are added. However, TraitMap::insert
and other methods were not included in this PR. I am waiting for this to get merged so I can start working on those.
while let Some(lexical_scope) = lexical_scope_opt { | ||
let result = Self::find_subfield_type_helper( | ||
lexical_scope, | ||
handler, | ||
engines, | ||
namespace, | ||
base_name, | ||
projections, | ||
)?; | ||
if let Some(result) = result { | ||
return Ok(result); | ||
} | ||
if let Some(parent_scope_id) = lexical_scope.parent { | ||
lexical_scope_opt = module.get_lexical_scope(parent_scope_id); | ||
} else { | ||
lexical_scope_opt = None; | ||
} | ||
} |
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 pattern
let mut lexical_scope_opt = ...;
while let Some(lexical_scope) = lexical_scope_opt {
...
if let Some(parent_scope_id) = lexical_scope.parent {
lexical_scope_opt = module.get_lexical_scope(parent_scope_id);
} else {
lexical_scope_opt = None;
}
}
is repeated in a couple of places, and seems to capture a structural aspect of hierarchical lexical scopes. Is there a way to abstract this pattern out (ideally so that it is located in the namespace module somewhere), so that traversing the scopes is kept separate from what we are searching for?
let mut lexical_scope_opt = Some(self.current_lexical_scope()); | ||
let mut vec = vec![]; | ||
while let Some(lexical_scope) = lexical_scope_opt { | ||
vec.extend( | ||
lexical_scope | ||
.items | ||
.implemented_traits | ||
.get_items_for_type(engines, type_id), | ||
); | ||
if let Some(parent_scope_id) = lexical_scope.parent { | ||
lexical_scope_opt = self.get_lexical_scope(parent_scope_id); | ||
} else { | ||
lexical_scope_opt = None; | ||
} | ||
} |
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 pattern occurs again here.
let mut lexical_scope_opt = Some(self.current_lexical_scope()); | ||
while let Some(lexical_scope) = lexical_scope_opt { | ||
let result = lexical_scope | ||
.items | ||
.resolve_symbol(handler, engines, symbol)?; | ||
if let Some(result) = result { | ||
return Ok(result); | ||
} | ||
if let Some(parent_scope_id) = lexical_scope.parent { | ||
lexical_scope_opt = self.get_lexical_scope(parent_scope_id); | ||
} else { | ||
lexical_scope_opt = None; | ||
} | ||
} |
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.
Same pattern again.
let mut lexical_scope_opt = Some(module.current_lexical_scope()); | ||
let mut all_impld_traits: BTreeSet<(Ident, TypeId)> = Default::default(); | ||
while let Some(lexical_scope) = lexical_scope_opt { | ||
all_impld_traits.extend( | ||
lexical_scope | ||
.items | ||
.implemented_traits | ||
.get_implemented_traits(type_id, engines), | ||
); | ||
if let Some(parent_scope_id) = lexical_scope.parent { | ||
lexical_scope_opt = module.get_lexical_scope(parent_scope_id); | ||
} else { | ||
lexical_scope_opt = None; | ||
} |
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.
Same pattern again.
Description
This PR implements a hierarchical-based trait map and namespace lookup system while type checking.
Previously we added the concept of lexical concepts, which store all the names in a tree-based hierarchy.
But currently we still rely on a single "global" namespace, which is maintained by the type check context as we go down the tree. Thus, so far, all trait and namespace lookup have relied on looking up in that single namespace.
The main idea here is to be able to just rely on the names existing in the lexical scopes, and walk up those lexical scope chains as we need to lookup any name or trait.
The logic is split into these two commits:
Implement hierarchical trait map lookups.
Implement hierarchical namespace lookups.
This PR still does not remove that cloning, which will be done in a separate future PR.
Checklist
Breaking*
orNew Feature
labels where relevant.