-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Rust: Make trait a base type mention of the self type parameter #19149
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
Conversation
f8b991c
to
91b1676
Compare
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.
Copilot wasn't able to review any files in this pull request.
Files not reviewed (4)
- rust/ql/lib/codeql/rust/internal/Type.qll: Language not supported
- rust/ql/lib/codeql/rust/internal/TypeInference.qll: Language not supported
- rust/ql/lib/codeql/rust/internal/TypeMention.qll: Language not supported
- rust/ql/test/library-tests/type-inference/type-inference.expected: Language not supported
Tip: Copilot only keeps its highest confidence comments to reduce noise and keep you focused. Learn more
91b1676
to
3db773d
Compare
3db773d
to
8acf9ce
Compare
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.
Very nice refactor, one small suggestion and question.
private predicate id(Raw::AstNode x, Raw::AstNode y) { x = y } | ||
|
||
private predicate idOfRaw(Raw::TypeParam x, int y) = equivalenceRelation(id/2)(x, y) | ||
private predicate idOfRaw(Raw::AstNode x, int y) = equivalenceRelation(id/2)(x, y) | ||
|
||
private int idOf(TypeParam node) { idOfRaw(Synth::convertAstNodeToRaw(node), result) } | ||
private int idOf(AstNode node) { idOfRaw(Synth::convertAstNodeToRaw(node), result) } |
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, instead of using AstNode
, it would be better to use something like
private import codeql.rust.elements.internal.generated.Synth
private class TTypeParamOrTrait = Synth::TTypeParam or Synth::TTrait;
private class TypeParamOrTrait extends AstNode, TTypeParamOrTrait { }
in order to reduce pressure on the equivalenceRelation
HOP.
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.
That makes sense. I remember that we also do equivalenceRelation
on Raw::AstNode
over in the CFG implementation. Perhaps it would make sense to factor that one out and reuse it for both CFG and type inference?
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.
In order to be properly shared, we would have to make it cached, I'm not sure we'd want 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.
Is it only the type of idOf
that should be changed? Not idOfRaw
and id
?
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've changed idOf
now. I picked at different name than TypeParamOrTrait
as we'll also have to add TypeAlias
es later when they become type parameters.
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.
idOfRaw
and id
should be updated as well, otherwise the equivalenceRelation
invocation will not be restricted.
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 sure how they should be updated to match the suggestion? I've changed idOfRaw
now such that it only applies to the relevant extensional predicates, but it doesn't look like the above.
exists(TraitItemNode trait | this = trait.getAnAssocItem() | | ||
typeParamMatchPosition(trait.getTypeParam(_), result, ppos) | ||
or | ||
ppos.isSelf() and result = TSelfTypeParameter(trait) |
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.
So, the Self
type parameter is now moved from the trait into each of the methods, which makes sense. But I wonder if this approach will also work once support for associated type defaults lands? E.g., in something like
trait MyTrait {
type T = Option<Self>
fn foo(self) -> T;
}
Perhaps it will Just Work with your other PR that introduced support for type aliases?
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 haven't thought of that. I don't think it will just work, but I think it can be made to work.
Associated types will be type parameters of the trait and the trait's methods, like this:
fn foo<Self : MyTrait<T>, T>(self) -> T
So we have to ensure that whatever makes Self
a MyTrait
has a type argument for T
and we should read that off of the default if nothing else is provided. So for an impl
block that uses the default it should behave as if the default was written for T
:
impl MyTrait<Option<Foo>> for Foo { ... }
cf3fb23
to
001735b
Compare
This PR changes how the
Self
parameter is handled in trait methods. Suppose some traitTrait<A>
. Today a method on this trait is handled like this (where the|
is some fictional syntax):The
self
parameter has the type of an implicitSelf
parameter and the trait type. On a call the passedself
is then matched as a "subtype" ofTrait<A>
to inferA
.With this PR the situration is now like this:
The
self
parameter only has theSelf
type and theSelf
type parameter now has the trait as a trait bound. This works since we can now handle trait bounds on type parameters, andA
is inferred through that.The biggest benefit of this is that we no longer infer superfluous types. For instance, we currently infer multiple return types for calls to trait methods that return
Self
: both the inferredSelf
type and the trait type itself. But the latter follows from the former. This reduction in type can be seen in the change to the.expected
file where all the trait types and their type arguments are now gone.