mirror of
https://github.com/github/codeql.git
synced 2026-02-12 05:01:06 +01:00
Merge pull request #21165 from paldepind/rust/associated-types
Rust: Associated types are inherited as type parameters by traits and dyn traits
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
private import codeql.rust.elements.internal.generated.Trait
|
||||
private import codeql.rust.internal.PathResolution as PathResolution
|
||||
|
||||
/**
|
||||
* INTERNAL: This module contains the customizable definition of `Trait` and should not
|
||||
@@ -67,5 +68,11 @@ module Impl {
|
||||
* `where` clauses for `Self`.
|
||||
*/
|
||||
TypeBound getATypeBound() { result = this.getTypeBound(_) }
|
||||
|
||||
/** Gets a direct supertrait of this trait, if any. */
|
||||
Trait getSupertrait() {
|
||||
result =
|
||||
PathResolution::resolvePath(this.getATypeBound().getTypeRepr().(PathTypeRepr).getPath())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,17 @@ private import codeql.rust.elements.internal.generated.Synth
|
||||
private import codeql.rust.frameworks.stdlib.Stdlib
|
||||
private import codeql.rust.frameworks.stdlib.Builtins as Builtins
|
||||
|
||||
/** Gets a type alias of `trait` or of a supertrait of `trait`. */
|
||||
private TypeAlias getTraitTypeAlias(Trait trait) {
|
||||
result = trait.getSupertrait*().getAssocItemList().getAnAssocItem()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a dyn trait type should have a type parameter associated with `n`. A
|
||||
* dyn trait type inherits the type parameters of the trait it implements. That
|
||||
* includes the type parameters corresponding to associated types.
|
||||
* Holds if a dyn trait type for the trait `trait` should have a type parameter
|
||||
* associated with `n`.
|
||||
*
|
||||
* A dyn trait type inherits the type parameters of the trait it implements.
|
||||
* That includes the type parameters corresponding to associated types.
|
||||
*
|
||||
* For instance in
|
||||
* ```rust
|
||||
@@ -24,10 +31,7 @@ private import codeql.rust.frameworks.stdlib.Builtins as Builtins
|
||||
*/
|
||||
private predicate dynTraitTypeParameter(Trait trait, AstNode n) {
|
||||
trait = any(DynTraitTypeRepr dt).getTrait() and
|
||||
(
|
||||
n = trait.getGenericParamList().getATypeParam() or
|
||||
n = trait.(TraitItemNode).getAnAssocItem().(TypeAlias)
|
||||
)
|
||||
n = [trait.getGenericParamList().getATypeParam().(AstNode), getTraitTypeAlias(trait)]
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -39,8 +43,10 @@ newtype TType =
|
||||
TNeverType() or
|
||||
TUnknownType() or
|
||||
TTypeParamTypeParameter(TypeParam t) or
|
||||
TAssociatedTypeTypeParameter(TypeAlias t) { any(TraitItemNode trait).getAnAssocItem() = t } or
|
||||
TDynTraitTypeParameter(AstNode n) { dynTraitTypeParameter(_, n) } or
|
||||
TAssociatedTypeTypeParameter(Trait trait, TypeAlias typeAlias) {
|
||||
getTraitTypeAlias(trait) = typeAlias
|
||||
} or
|
||||
TDynTraitTypeParameter(Trait trait, AstNode n) { dynTraitTypeParameter(trait, n) } or
|
||||
TImplTraitTypeParameter(ImplTraitTypeRepr implTrait, TypeParam tp) {
|
||||
implTraitTypeParam(implTrait, _, tp)
|
||||
} or
|
||||
@@ -270,17 +276,10 @@ class DynTraitType extends Type, TDynTraitType {
|
||||
DynTraitType() { this = TDynTraitType(trait) }
|
||||
|
||||
override DynTraitTypeParameter getPositionalTypeParameter(int i) {
|
||||
result = TDynTraitTypeParameter(trait.getGenericParamList().getTypeParam(i))
|
||||
result.getTypeParam() = trait.getGenericParamList().getTypeParam(i)
|
||||
}
|
||||
|
||||
override TypeParameter getATypeParameter() {
|
||||
result = super.getATypeParameter()
|
||||
or
|
||||
exists(AstNode n |
|
||||
dynTraitTypeParameter(trait, n) and
|
||||
result = TDynTraitTypeParameter(n)
|
||||
)
|
||||
}
|
||||
override DynTraitTypeParameter getATypeParameter() { result.getTrait() = trait }
|
||||
|
||||
Trait getTrait() { result = trait }
|
||||
|
||||
@@ -427,30 +426,54 @@ class TypeParamTypeParameter extends TypeParameter, TTypeParamTypeParameter {
|
||||
* // ...
|
||||
* }
|
||||
* ```
|
||||
* Furthermore, associated types of a supertrait induce a corresponding type
|
||||
* parameter in any subtraits. E.g., if we have a trait `SubTrait: ATrait` then
|
||||
* `SubTrait` also has a type parameter for the associated type
|
||||
* `AssociatedType`.
|
||||
*/
|
||||
class AssociatedTypeTypeParameter extends TypeParameter, TAssociatedTypeTypeParameter {
|
||||
private Trait trait;
|
||||
private TypeAlias typeAlias;
|
||||
|
||||
AssociatedTypeTypeParameter() { this = TAssociatedTypeTypeParameter(typeAlias) }
|
||||
AssociatedTypeTypeParameter() { this = TAssociatedTypeTypeParameter(trait, typeAlias) }
|
||||
|
||||
TypeAlias getTypeAlias() { result = typeAlias }
|
||||
|
||||
/** Gets the trait that contains this associated type declaration. */
|
||||
TraitItemNode getTrait() { result.getAnAssocItem() = typeAlias }
|
||||
TraitItemNode getTrait() { result = trait }
|
||||
|
||||
override ItemNode getDeclaringItem() { result = this.getTrait() }
|
||||
/**
|
||||
* Holds if this associated type type parameter corresponds directly its
|
||||
* trait, that is, it is not inherited from a supertrait.
|
||||
*/
|
||||
predicate isDirect() { trait.(TraitItemNode).getAnAssocItem() = typeAlias }
|
||||
|
||||
override string toString() { result = typeAlias.getName().getText() }
|
||||
override ItemNode getDeclaringItem() { result = trait }
|
||||
|
||||
override string toString() {
|
||||
result = typeAlias.getName().getText() + "[" + trait.getName().toString() + "]"
|
||||
}
|
||||
|
||||
override Location getLocation() { result = typeAlias.getLocation() }
|
||||
}
|
||||
|
||||
/** Gets the associated type type-parameter corresponding directly to `typeAlias`. */
|
||||
AssociatedTypeTypeParameter getAssociatedTypeTypeParameter(TypeAlias typeAlias) {
|
||||
result.isDirect() and result.getTypeAlias() = typeAlias
|
||||
}
|
||||
|
||||
/** Gets the dyn type type-parameter corresponding directly to `typeAlias`. */
|
||||
DynTraitTypeParameter getDynTraitTypeParameter(TypeAlias typeAlias) {
|
||||
result.getTraitTypeParameter() = getAssociatedTypeTypeParameter(typeAlias)
|
||||
}
|
||||
|
||||
class DynTraitTypeParameter extends TypeParameter, TDynTraitTypeParameter {
|
||||
private Trait trait;
|
||||
private AstNode n;
|
||||
|
||||
DynTraitTypeParameter() { this = TDynTraitTypeParameter(n) }
|
||||
DynTraitTypeParameter() { this = TDynTraitTypeParameter(trait, n) }
|
||||
|
||||
Trait getTrait() { dynTraitTypeParameter(result, n) }
|
||||
Trait getTrait() { result = trait }
|
||||
|
||||
/** Gets the dyn trait type that this type parameter belongs to. */
|
||||
DynTraitType getDynTraitType() { result.getTrait() = this.getTrait() }
|
||||
@@ -465,7 +488,7 @@ class DynTraitTypeParameter extends TypeParameter, TDynTraitTypeParameter {
|
||||
TypeParameter getTraitTypeParameter() {
|
||||
result.(TypeParamTypeParameter).getTypeParam() = n
|
||||
or
|
||||
result.(AssociatedTypeTypeParameter).getTypeAlias() = n
|
||||
result = TAssociatedTypeTypeParameter(trait, n)
|
||||
}
|
||||
|
||||
private string toStringInner() {
|
||||
|
||||
@@ -90,7 +90,7 @@ private module Input1 implements InputSig1<Location> {
|
||||
tp =
|
||||
rank[result](TypeParameter tp0, int kind, int id1, int id2 |
|
||||
kind = 1 and
|
||||
id1 = 0 and
|
||||
id1 = idOfTypeParameterAstNode(tp0.(DynTraitTypeParameter).getTrait()) and
|
||||
id2 =
|
||||
idOfTypeParameterAstNode([
|
||||
tp0.(DynTraitTypeParameter).getTypeParam().(AstNode),
|
||||
@@ -102,10 +102,13 @@ private module Input1 implements InputSig1<Location> {
|
||||
id2 = idOfTypeParameterAstNode(tp0.(ImplTraitTypeParameter).getTypeParam())
|
||||
or
|
||||
kind = 3 and
|
||||
id1 = idOfTypeParameterAstNode(tp0.(AssociatedTypeTypeParameter).getTrait()) and
|
||||
id2 = idOfTypeParameterAstNode(tp0.(AssociatedTypeTypeParameter).getTypeAlias())
|
||||
or
|
||||
kind = 4 and
|
||||
id1 = 0 and
|
||||
exists(AstNode node | id2 = idOfTypeParameterAstNode(node) |
|
||||
node = tp0.(TypeParamTypeParameter).getTypeParam() or
|
||||
node = tp0.(AssociatedTypeTypeParameter).getTypeAlias() or
|
||||
node = tp0.(SelfTypeParameter).getTrait() or
|
||||
node = tp0.(ImplTraitTypeTypeParameter).getImplTraitTypeRepr()
|
||||
)
|
||||
@@ -3507,12 +3510,12 @@ private DynTraitType getFutureTraitType() { result.getTrait() instanceof FutureT
|
||||
|
||||
pragma[nomagic]
|
||||
private AssociatedTypeTypeParameter getFutureOutputTypeParameter() {
|
||||
result.getTypeAlias() = any(FutureTrait ft).getOutputType()
|
||||
result = getAssociatedTypeTypeParameter(any(FutureTrait ft).getOutputType())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private DynTraitTypeParameter getDynFutureOutputTypeParameter() {
|
||||
result = TDynTraitTypeParameter(any(FutureTrait ft).getOutputType())
|
||||
result.getTraitTypeParameter() = getFutureOutputTypeParameter()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -3824,20 +3827,20 @@ private Type invokedClosureFnTypeAt(InvokedClosureExpr ce, TypePath path) {
|
||||
|
||||
/** Gets the path to a closure's return type. */
|
||||
private TypePath closureReturnPath() {
|
||||
result = TypePath::singleton(TDynTraitTypeParameter(any(FnOnceTrait t).getOutputType()))
|
||||
result = TypePath::singleton(getDynTraitTypeParameter(any(FnOnceTrait t).getOutputType()))
|
||||
}
|
||||
|
||||
/** Gets the path to a closure with arity `arity`s `index`th parameter type. */
|
||||
pragma[nomagic]
|
||||
private TypePath closureParameterPath(int arity, int index) {
|
||||
result =
|
||||
TypePath::cons(TDynTraitTypeParameter(any(FnOnceTrait t).getTypeParam()),
|
||||
TypePath::cons(TDynTraitTypeParameter(_, any(FnOnceTrait t).getTypeParam()),
|
||||
TypePath::singleton(getTupleTypeParameter(arity, index)))
|
||||
}
|
||||
|
||||
/** Gets the path to the return type of the `FnOnce` trait. */
|
||||
private TypePath fnReturnPath() {
|
||||
result = TypePath::singleton(TAssociatedTypeTypeParameter(any(FnOnceTrait t).getOutputType()))
|
||||
result = TypePath::singleton(getAssociatedTypeTypeParameter(any(FnOnceTrait t).getOutputType()))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3898,7 +3901,7 @@ private Type inferClosureExprType(AstNode n, TypePath path) {
|
||||
result = TDynTraitType(any(FnOnceTrait t)) // always exists because of the mention in `builtins/mentions.rs`
|
||||
or
|
||||
n = ce and
|
||||
path = TypePath::singleton(TDynTraitTypeParameter(any(FnOnceTrait t).getTypeParam())) and
|
||||
path = TypePath::singleton(TDynTraitTypeParameter(_, any(FnOnceTrait t).getTypeParam())) and
|
||||
result.(TupleType).getArity() = ce.getNumberOfParams()
|
||||
or
|
||||
// Propagate return type annotation to body
|
||||
|
||||
@@ -18,6 +18,8 @@ query predicate illFormedTypeMention(TypeMention tm) {
|
||||
any(PathTypeMention ptm |
|
||||
exists(ptm.resolvePathTypeAt(TypePath::nil())) and
|
||||
not exists(ptm.resolveType())
|
||||
or
|
||||
ptm.(NonAliasPathTypeMention).getResolved() instanceof TypeAlias
|
||||
) and
|
||||
// Only include inconsistencies in the source, as we otherwise get
|
||||
// inconsistencies from library code in every project.
|
||||
|
||||
@@ -148,30 +148,11 @@ class NonAliasPathTypeMention extends PathTypeMention {
|
||||
|
||||
TypeItemNode getResolved() { result = resolved }
|
||||
|
||||
/**
|
||||
* Gets a type alias with the name `name` of the trait that this path resolves
|
||||
* to, if any.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private TypeAlias getResolvedTraitAlias(string name) {
|
||||
result = resolved.(TraitItemNode).getAnAssocItem() and
|
||||
name = result.getName().getText()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private TypeRepr getAssocTypeArg(string name) {
|
||||
private TypeMention getAssocTypeArg(string name) {
|
||||
result = this.getSegment().getGenericArgList().getAssocTypeArg(name)
|
||||
}
|
||||
|
||||
/** Gets the type argument for the associated type `alias`, if any. */
|
||||
pragma[nomagic]
|
||||
private TypeRepr getAnAssocTypeArgument(TypeAlias alias) {
|
||||
exists(string name |
|
||||
alias = this.getResolvedTraitAlias(name) and
|
||||
result = this.getAssocTypeArg(name)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type mention that instantiates the implicit `Self` type parameter
|
||||
* for this path, if it occurs in the position of a trait bound.
|
||||
@@ -239,7 +220,7 @@ class NonAliasPathTypeMention extends PathTypeMention {
|
||||
tp = TTypeParamTypeParameter(t.getTypeParam()) and
|
||||
result = s.getParenthesizedArgList().(TypeMention).resolveTypeAt(path)
|
||||
or
|
||||
tp = TAssociatedTypeTypeParameter(t.getOutputType()) and
|
||||
tp = TAssociatedTypeTypeParameter(t, t.getOutputType()) and
|
||||
(
|
||||
result = s.getRetType().getTypeRepr().(TypeMention).resolveTypeAt(path)
|
||||
or
|
||||
@@ -249,19 +230,47 @@ class NonAliasPathTypeMention extends PathTypeMention {
|
||||
path.isEmpty()
|
||||
)
|
||||
)
|
||||
or
|
||||
// If `path` is the supertrait of a trait block then any associated types
|
||||
// of the supertrait should be instantiated with the subtrait's
|
||||
// corresponding copies.
|
||||
//
|
||||
// As an example, for
|
||||
// ```rust
|
||||
// trait Sub: Super {
|
||||
// // ^^^^^ this
|
||||
// ```
|
||||
// we do something to the effect of:
|
||||
// ```rust
|
||||
// trait Sub: Super<Assoc=Assoc[Sub]>
|
||||
// ```
|
||||
// Where `Assoc` is an associated type of `Super` and `Assoc[Sub]` denotes
|
||||
// the copy of the type parameter inherited by `Sub`.
|
||||
exists(Trait subtrait, TypeAlias alias |
|
||||
subtrait.getATypeBound().getTypeRepr().(PathTypeRepr).getPath() = this and
|
||||
result = TAssociatedTypeTypeParameter(subtrait, alias) and
|
||||
tp = TAssociatedTypeTypeParameter(resolved, alias) and
|
||||
path.isEmpty()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
bindingset[name]
|
||||
private TypeAlias getResolvedAlias(string name) {
|
||||
result = resolved.(TraitItemNode).getAssocItem(name)
|
||||
}
|
||||
|
||||
bindingset[name]
|
||||
private TypeAlias getResolvedTraitAssocType(string name) {
|
||||
result = resolved.(TraitItemNode).getASuccessor(name)
|
||||
}
|
||||
|
||||
/** Gets the type mention in this path for the type parameter `tp`, if any. */
|
||||
pragma[nomagic]
|
||||
private TypeMention getTypeMentionForTypeParameter(TypeParameter tp) {
|
||||
exists(TypeAlias alias |
|
||||
result = this.getAnAssocTypeArgument(alias) and
|
||||
tp = TAssociatedTypeTypeParameter(alias)
|
||||
exists(TypeAlias alias, string name |
|
||||
result = this.getAssocTypeArg(name) and
|
||||
tp = TAssociatedTypeTypeParameter(resolved, alias) and
|
||||
alias = this.getResolvedTraitAssocType(name)
|
||||
)
|
||||
or
|
||||
// If `path` is the trait of an `impl` block then any associated types
|
||||
@@ -279,9 +288,9 @@ class NonAliasPathTypeMention extends PathTypeMention {
|
||||
// the rhs. of the type alias is a type argument to the trait.
|
||||
exists(ImplItemNode impl, TypeAlias alias, string name |
|
||||
this = impl.getTraitPath() and
|
||||
alias = impl.getASuccessor(pragma[only_bind_into](name)) and
|
||||
alias = impl.getASuccessor(name) and
|
||||
result = alias.getTypeRepr() and
|
||||
tp = TAssociatedTypeTypeParameter(this.getResolvedAlias(pragma[only_bind_into](name)))
|
||||
tp = TAssociatedTypeTypeParameter(resolved, this.getResolvedAlias(name))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -299,7 +308,7 @@ class NonAliasPathTypeMention extends PathTypeMention {
|
||||
or
|
||||
result = TTypeParamTypeParameter(resolved)
|
||||
or
|
||||
result = TAssociatedTypeTypeParameter(resolved)
|
||||
result = TAssociatedTypeTypeParameter(resolvePath(this.getQualifier()), resolved)
|
||||
}
|
||||
|
||||
override Type resolvePathTypeAt(TypePath typePath) {
|
||||
@@ -384,9 +393,8 @@ class TraitMention extends TypeMention instanceof TraitItemNode {
|
||||
result = TSelfTypeParameter(this)
|
||||
or
|
||||
exists(TypeAlias alias |
|
||||
alias = super.getAnAssocItem() and
|
||||
typePath = TypePath::singleton(result) and
|
||||
result = TAssociatedTypeTypeParameter(alias)
|
||||
result = TAssociatedTypeTypeParameter(this, alias)
|
||||
)
|
||||
or
|
||||
exists(TypeParam tp |
|
||||
@@ -540,7 +548,7 @@ class DynTraitTypeReprMention extends TypeMention instanceof DynTraitTypeRepr {
|
||||
// impl<A, B, ..> Trait<A, B, ..> for (dyn Trait)<A, B, ..>
|
||||
// ```
|
||||
// To achieve this:
|
||||
// - `DynTypeAbstraction` is an abstraction over type parameters of the trait.
|
||||
// - `DynTypeAbstraction` is an abstraction over the type parameters of the trait.
|
||||
// - `DynTypeBoundListMention` (this class) is a type mention which has `dyn
|
||||
// Trait` at the root and which for every type parameter of `dyn Trait` has the
|
||||
// corresponding type parameter of the trait.
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
multipleResolvedTargets
|
||||
| main.rs:3087:13:3087:17 | x.f() |
|
||||
| main.rs:2860:13:2860:17 | x.f() |
|
||||
|
||||
364
rust/ql/test/library-tests/type-inference/associated_types.rs
Normal file
364
rust/ql/test/library-tests/type-inference/associated_types.rs
Normal file
@@ -0,0 +1,364 @@
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
struct Wrapper<A>(A);
|
||||
|
||||
impl<A> Wrapper<A> {
|
||||
fn unwrap(self) -> A {
|
||||
self.0 // $ fieldof=Wrapper
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct S;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct S2;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct S3;
|
||||
|
||||
trait GetSet {
|
||||
type Output;
|
||||
|
||||
// GetSet::get
|
||||
fn get(&self) -> Self::Output;
|
||||
|
||||
// GetSet::set
|
||||
fn set(&self, _a: Self::Output) {}
|
||||
}
|
||||
|
||||
fn get<O, T: GetSet<Output = O> + ?Sized>(item: &T) -> O {
|
||||
item.get() // $ target=GetSet::get
|
||||
}
|
||||
|
||||
trait AnotherGet: GetSet {
|
||||
type AnotherOutput;
|
||||
|
||||
// AnotherGet::get_another
|
||||
fn get_another(&self) -> Self::AnotherOutput;
|
||||
}
|
||||
|
||||
impl GetSet for S {
|
||||
type Output = S3;
|
||||
|
||||
// S::get
|
||||
fn get(&self) -> Self::Output {
|
||||
S3
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy> GetSet for Wrapper<T> {
|
||||
type Output = T;
|
||||
|
||||
// Wrapper::get
|
||||
fn get(&self) -> Self::Output {
|
||||
self.0 // $ fieldof=Wrapper
|
||||
}
|
||||
}
|
||||
|
||||
mod default_method_using_associated_type {
|
||||
use super::*;
|
||||
|
||||
trait MyTrait {
|
||||
type AssociatedType;
|
||||
|
||||
// MyTrait::m1
|
||||
fn m1(self) -> Self::AssociatedType;
|
||||
|
||||
fn m2(self) -> Self::AssociatedType
|
||||
where
|
||||
Self::AssociatedType: Default,
|
||||
Self: Sized,
|
||||
{
|
||||
self.m1(); // $ target=MyTrait::m1 type=self.m1():AssociatedType[MyTrait]
|
||||
let _default = Self::AssociatedType::default(); // $ MISSING: target=default _default:AssociatedType
|
||||
Self::AssociatedType::default() // $ MISSING: target=default
|
||||
}
|
||||
}
|
||||
|
||||
impl MyTrait for S {
|
||||
type AssociatedType = S3;
|
||||
|
||||
// S::m1
|
||||
fn m1(self) -> Self::AssociatedType {
|
||||
S3
|
||||
}
|
||||
}
|
||||
|
||||
impl MyTrait for S2 {
|
||||
// Associated type definition with a type argument
|
||||
type AssociatedType = Wrapper<S2>;
|
||||
|
||||
fn m1(self) -> Self::AssociatedType {
|
||||
Wrapper(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test() {
|
||||
let x1 = S;
|
||||
// Call to method in `impl` block
|
||||
println!("{:?}", x1.m1()); // $ target=S::m1 type=x1.m1():S3
|
||||
|
||||
let x2 = S;
|
||||
// Call to default method in `trait` block
|
||||
let y = x2.m2(); // $ target=m2 type=y:S3
|
||||
println!("{:?}", y);
|
||||
|
||||
let x5 = S2;
|
||||
println!("{:?}", x5.m1()); // $ target=m1 type=x5.m1():A.S2
|
||||
let x6 = S2;
|
||||
println!("{:?}", x6.m2()); // $ target=m2 type=x6.m2():A.S2
|
||||
}
|
||||
}
|
||||
|
||||
// Tests for signatures that access associated types from type parameters
|
||||
mod type_param_access_associated_type {
|
||||
use super::*;
|
||||
|
||||
fn tp_with_as<T: GetSet>(thing: T) -> <T as GetSet>::Output {
|
||||
thing.get() // $ target=GetSet::get
|
||||
}
|
||||
|
||||
fn tp_without_as<T: GetSet>(thing: T) -> T::Output {
|
||||
thing.get() // $ target=GetSet::get
|
||||
}
|
||||
|
||||
pub fn test() {
|
||||
let _o1 = tp_with_as(S); // $ target=tp_with_as MISSING: type=_o1:S3
|
||||
let _o2 = tp_without_as(S); // $ target=tp_without_as MISSING: type=_o2:S3
|
||||
}
|
||||
}
|
||||
|
||||
// Tests for specifying associated types using equalities, e.g., `Trait<AssocType = Type>`
|
||||
mod equality_on_associated_type {
|
||||
use super::*;
|
||||
|
||||
fn _in_same_trait<T>(x: T)
|
||||
where
|
||||
T: GetSet<Output = char>,
|
||||
{
|
||||
let _a = x.get(); // $ target=GetSet::get type=_a:char
|
||||
}
|
||||
|
||||
// Here we specify `Output` from `GetSet` through the subtrait `AnotherGet`.
|
||||
fn _in_subtrait<T>(x: T)
|
||||
where
|
||||
T: AnotherGet<Output = i32, AnotherOutput = bool>,
|
||||
{
|
||||
let _a1 = x.get(); // $ target=GetSet::get type=_a1:i32
|
||||
let _a2 = get(&x); // $ target=get type=_a2:i32
|
||||
let _b = x.get_another(); // $ type=_b:bool target=AnotherGet::get_another
|
||||
}
|
||||
|
||||
// Here we specify the associated types as two separate trait bounds
|
||||
fn _two_bounds<T>(x: T)
|
||||
where
|
||||
T: AnotherGet<AnotherOutput = bool>,
|
||||
T: GetSet<Output = i32>,
|
||||
{
|
||||
let _a1 = x.get(); // $ target=GetSet::get type=_a1:i32
|
||||
let _a2 = get(&x); // $ target=get type=_a2:i32
|
||||
let _b = x.get_another(); // $ type=_b:bool target=AnotherGet::get_another
|
||||
}
|
||||
|
||||
trait AssocNameClash: GetSet {
|
||||
type Output; // This name clashes with GetSet::Output
|
||||
|
||||
// AssocNameClash::get2
|
||||
fn get2(&self) -> <Self as AssocNameClash>::Output;
|
||||
}
|
||||
|
||||
fn _two_bounds_name_clash<T>(x: T)
|
||||
where
|
||||
T: AssocNameClash<Output = char>,
|
||||
T: GetSet<Output = i32>,
|
||||
{
|
||||
let _a = x.get(); // $ type=_a:i32 target=GetSet::get
|
||||
let _b = x.get2(); // $ target=AssocNameClash::get2 MISSING: type=_b:char
|
||||
}
|
||||
}
|
||||
|
||||
mod generic_associated_type {
|
||||
use super::*;
|
||||
|
||||
trait MyTraitAssoc2 {
|
||||
type GenericAssociatedType<AssociatedParam>;
|
||||
|
||||
// MyTraitAssoc2::put
|
||||
fn put<A>(&self, a: A) -> Self::GenericAssociatedType<A>;
|
||||
|
||||
// MyTraitAssoc2::put_two
|
||||
fn put_two<A>(&self, a: A, b: A) -> Self::GenericAssociatedType<A> {
|
||||
self.put(a); // $ target=MyTraitAssoc2::put
|
||||
self.put(b) // $ target=MyTraitAssoc2::put
|
||||
}
|
||||
}
|
||||
|
||||
impl MyTraitAssoc2 for S {
|
||||
// Associated type with a type parameter
|
||||
type GenericAssociatedType<AssociatedParam> = Wrapper<AssociatedParam>;
|
||||
|
||||
// S::put
|
||||
fn put<A>(&self, a: A) -> Wrapper<A> {
|
||||
Wrapper(a)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test() {
|
||||
let s = S;
|
||||
// Call to the method in `impl` block
|
||||
let _g1 = s.put(1i32); // $ target=S::put type=_g1:A.i32
|
||||
|
||||
// Call to default implementation in `trait` block
|
||||
let _g2 = s.put_two(true, false); // $ target=MyTraitAssoc2::put_two MISSING: type=_g2:A.bool
|
||||
}
|
||||
}
|
||||
|
||||
mod multiple_associated_types {
|
||||
use super::*;
|
||||
|
||||
// A generic trait with multiple associated types.
|
||||
trait TraitMultipleAssoc<TrG> {
|
||||
type Assoc1;
|
||||
type Assoc2;
|
||||
|
||||
fn get_zero(&self) -> TrG;
|
||||
|
||||
fn get_one(&self) -> Self::Assoc1;
|
||||
|
||||
fn get_two(&self) -> Self::Assoc2;
|
||||
}
|
||||
|
||||
impl TraitMultipleAssoc<S3> for S3 {
|
||||
type Assoc1 = S;
|
||||
type Assoc2 = S2;
|
||||
|
||||
fn get_zero(&self) -> S3 {
|
||||
S3
|
||||
}
|
||||
|
||||
fn get_one(&self) -> Self::Assoc1 {
|
||||
S
|
||||
}
|
||||
|
||||
fn get_two(&self) -> Self::Assoc2 {
|
||||
S2
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test() {
|
||||
let _assoc_zero = S3.get_zero(); // $ target=get_zero type=_assoc_zero:S3
|
||||
let _assoc_one = S3.get_one(); // $ target=get_one type=_assoc_one:S
|
||||
let _assoc_two = S3.get_two(); // $ target=get_two type=_assoc_two:S2
|
||||
}
|
||||
}
|
||||
|
||||
mod associated_type_in_supertrait {
|
||||
use super::*;
|
||||
|
||||
trait Subtrait: GetSet {
|
||||
// Subtrait::get_content
|
||||
fn get_content(&self) -> Self::Output;
|
||||
}
|
||||
|
||||
// A subtrait declared using a `where` clause.
|
||||
trait Subtrait2
|
||||
where
|
||||
Self: GetSet,
|
||||
{
|
||||
// Subtrait2::insert_two
|
||||
fn insert_two(&self, c1: Self::Output, c2: Self::Output) {
|
||||
self.set(c1); // $ target=GetSet::set
|
||||
self.set(c2); // $ target=GetSet::set
|
||||
}
|
||||
}
|
||||
|
||||
struct MyType<T>(T);
|
||||
|
||||
impl<T: Copy> GetSet for MyType<T> {
|
||||
type Output = T;
|
||||
|
||||
fn get(&self) -> Self::Output {
|
||||
self.0 // $ fieldof=MyType
|
||||
}
|
||||
|
||||
fn set(&self, _content: Self::Output) {
|
||||
println!("Inserting content: ");
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy> Subtrait for MyType<T> {
|
||||
// MyType::get_content
|
||||
fn get_content(&self) -> Self::Output {
|
||||
(*self).0 // $ fieldof=MyType target=deref
|
||||
}
|
||||
}
|
||||
|
||||
fn get_content<T: Subtrait>(item: &T) -> T::Output {
|
||||
item.get_content() // $ target=Subtrait::get_content
|
||||
}
|
||||
|
||||
fn insert_three<T: Subtrait2>(item: &T, c1: T::Output, c2: T::Output, c3: T::Output) {
|
||||
item.set(c1); // $ target=GetSet::set
|
||||
item.insert_two(c2, c3); // $ target=Subtrait2::insert_two
|
||||
}
|
||||
|
||||
pub fn test() {
|
||||
let item1 = MyType(42i64);
|
||||
let _content1 = item1.get_content(); // $ target=MyType::get_content MISSING: type=_content1:i64
|
||||
|
||||
let item2 = MyType(true);
|
||||
let _content2 = get_content(&item2); // $ target=get_content MISSING: type=_content2:bool
|
||||
}
|
||||
}
|
||||
|
||||
mod generic_associated_type_name_clash {
|
||||
use super::*;
|
||||
|
||||
struct ST<T>(T);
|
||||
|
||||
impl<Output: Copy> GetSet for ST<Output> {
|
||||
// This is not a recursive type, the `Output` on the right-hand side
|
||||
// refers to the type parameter of the impl block just above.
|
||||
type Output = Result<Output, Output>;
|
||||
|
||||
fn get(&self) -> Self::Output {
|
||||
Ok(self.0) // $ fieldof=ST type=Ok(...):Result type=Ok(...):T.Output type=Ok(...):E.Output
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test() {
|
||||
let _y = ST(true).get(); // $ type=_y:Result type=_y:T.bool type=_y:E.bool target=get
|
||||
}
|
||||
}
|
||||
|
||||
// Tests for associated types in `dyn` trait objects
|
||||
mod dyn_trait {
|
||||
use super::*;
|
||||
|
||||
fn _assoc_type_from_trait(t: &dyn GetSet<Output = i32>) {
|
||||
// Explicit deref
|
||||
let _a1 = (*t).get(); // $ target=deref target=GetSet::get type=_a1:i32
|
||||
|
||||
// Auto-deref
|
||||
let _a2 = t.get(); // $ target=GetSet::get type=_a2:i32
|
||||
|
||||
let _a3 = get(t); // $ target=get type=_a3:i32
|
||||
}
|
||||
|
||||
fn _assoc_type_from_supertrait(t: &dyn AnotherGet<Output = i32, AnotherOutput = bool>) {
|
||||
let _a1 = (*t).get(); // $ target=deref target=GetSet::get type=_a1:i32
|
||||
let _a2 = t.get(); // $ target=GetSet::get type=_a2:i32
|
||||
let _a3 = get(t); // $ target=get type=_a3:i32
|
||||
let _b1 = (*t).get_another(); // $ target=deref target=AnotherGet::get_another type=_b1:bool
|
||||
let _b2 = t.get_another(); // $ target=AnotherGet::get_another type=_b2:bool
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test() {
|
||||
default_method_using_associated_type::test(); // $ target=test
|
||||
type_param_access_associated_type::test(); // $ target=test
|
||||
generic_associated_type::test(); // $ target=test
|
||||
multiple_associated_types::test(); // $ target=test
|
||||
associated_type_in_supertrait::test(); // $ target=test
|
||||
generic_associated_type_name_clash::test(); // $ target=test
|
||||
}
|
||||
@@ -903,214 +903,6 @@ mod function_trait_bounds {
|
||||
}
|
||||
}
|
||||
|
||||
mod associated_type_in_trait {
|
||||
#[derive(Debug)]
|
||||
struct Wrapper<A> {
|
||||
field: A,
|
||||
}
|
||||
|
||||
impl<A> Wrapper<A> {
|
||||
fn unwrap(self) -> A {
|
||||
self.field // $ fieldof=Wrapper
|
||||
}
|
||||
}
|
||||
|
||||
trait MyTrait {
|
||||
type AssociatedType;
|
||||
|
||||
// MyTrait::m1
|
||||
fn m1(self) -> Self::AssociatedType;
|
||||
|
||||
fn m2(self) -> Self::AssociatedType
|
||||
where
|
||||
Self::AssociatedType: Default,
|
||||
Self: Sized,
|
||||
{
|
||||
self.m1(); // $ target=MyTrait::m1 type=self.m1():AssociatedType
|
||||
Self::AssociatedType::default()
|
||||
}
|
||||
}
|
||||
|
||||
trait MyTraitAssoc2 {
|
||||
type GenericAssociatedType<AssociatedParam>;
|
||||
|
||||
// MyTrait::put
|
||||
fn put<A>(&self, a: A) -> Self::GenericAssociatedType<A>;
|
||||
|
||||
fn putTwo<A>(&self, a: A, b: A) -> Self::GenericAssociatedType<A> {
|
||||
self.put(a); // $ target=MyTrait::put
|
||||
self.put(b) // $ target=MyTrait::put
|
||||
}
|
||||
}
|
||||
|
||||
// A generic trait with multiple associated types.
|
||||
trait TraitMultipleAssoc<TrG> {
|
||||
type Assoc1;
|
||||
type Assoc2;
|
||||
|
||||
fn get_zero(&self) -> TrG;
|
||||
|
||||
fn get_one(&self) -> Self::Assoc1;
|
||||
|
||||
fn get_two(&self) -> Self::Assoc2;
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct S;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct S2;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct AT;
|
||||
|
||||
impl MyTrait for S {
|
||||
type AssociatedType = AT;
|
||||
|
||||
// S::m1
|
||||
fn m1(self) -> Self::AssociatedType {
|
||||
AT
|
||||
}
|
||||
}
|
||||
|
||||
impl MyTraitAssoc2 for S {
|
||||
// Associated type with a type parameter
|
||||
type GenericAssociatedType<AssociatedParam> = Wrapper<AssociatedParam>;
|
||||
|
||||
// S::put
|
||||
fn put<A>(&self, a: A) -> Wrapper<A> {
|
||||
Wrapper { field: a }
|
||||
}
|
||||
}
|
||||
|
||||
impl MyTrait for S2 {
|
||||
// Associated type definition with a type argument
|
||||
type AssociatedType = Wrapper<S2>;
|
||||
|
||||
fn m1(self) -> Self::AssociatedType {
|
||||
Wrapper { field: self }
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: This implementation is just to make it possible to call `m2` on `S2.`
|
||||
impl Default for Wrapper<S2> {
|
||||
fn default() -> Self {
|
||||
Wrapper { field: S2 }
|
||||
}
|
||||
}
|
||||
|
||||
// Function that returns an associated type from a trait bound
|
||||
|
||||
fn g<T: MyTrait>(thing: T) -> <T as MyTrait>::AssociatedType {
|
||||
thing.m1() // $ target=MyTrait::m1
|
||||
}
|
||||
|
||||
impl TraitMultipleAssoc<AT> for AT {
|
||||
type Assoc1 = S;
|
||||
type Assoc2 = S2;
|
||||
|
||||
fn get_zero(&self) -> AT {
|
||||
AT
|
||||
}
|
||||
|
||||
fn get_one(&self) -> Self::Assoc1 {
|
||||
S
|
||||
}
|
||||
|
||||
fn get_two(&self) -> Self::Assoc2 {
|
||||
S2
|
||||
}
|
||||
}
|
||||
|
||||
pub fn f() {
|
||||
let x1 = S;
|
||||
// Call to method in `impl` block
|
||||
println!("{:?}", x1.m1()); // $ target=S::m1 type=x1.m1():AT
|
||||
|
||||
let x2 = S;
|
||||
// Call to default method in `trait` block
|
||||
let y = x2.m2(); // $ target=m2 type=y:AT
|
||||
println!("{:?}", y);
|
||||
|
||||
let x3 = S;
|
||||
// Call to the method in `impl` block
|
||||
println!("{:?}", x3.put(1).unwrap()); // $ target=S::put target=unwrap
|
||||
|
||||
// Call to default implementation in `trait` block
|
||||
println!("{:?}", x3.putTwo(2, 3).unwrap()); // $ target=putTwo target=unwrap
|
||||
|
||||
let x4 = g(S); // $ target=g $ MISSING: type=x4:AT
|
||||
println!("{:?}", x4);
|
||||
|
||||
let x5 = S2;
|
||||
println!("{:?}", x5.m1()); // $ target=m1 type=x5.m1():A.S2
|
||||
let x6 = S2;
|
||||
println!("{:?}", x6.m2()); // $ target=m2 type=x6.m2():A.S2
|
||||
|
||||
let assoc_zero = AT.get_zero(); // $ target=get_zero type=assoc_zero:AT
|
||||
let assoc_one = AT.get_one(); // $ target=get_one type=assoc_one:S
|
||||
let assoc_two = AT.get_two(); // $ target=get_two type=assoc_two:S2
|
||||
}
|
||||
}
|
||||
|
||||
mod associated_type_in_supertrait {
|
||||
trait Supertrait {
|
||||
type Content;
|
||||
// Supertrait::insert
|
||||
fn insert(&self, content: Self::Content);
|
||||
}
|
||||
|
||||
trait Subtrait: Supertrait {
|
||||
// Subtrait::get_content
|
||||
fn get_content(&self) -> Self::Content;
|
||||
}
|
||||
|
||||
// A subtrait declared using a `where` clause.
|
||||
trait Subtrait2
|
||||
where
|
||||
Self: Supertrait,
|
||||
{
|
||||
// Subtrait2::insert_two
|
||||
fn insert_two(&self, c1: Self::Content, c2: Self::Content) {
|
||||
self.insert(c1); // $ target=Supertrait::insert
|
||||
self.insert(c2); // $ target=Supertrait::insert
|
||||
}
|
||||
}
|
||||
|
||||
struct MyType<T>(T);
|
||||
|
||||
impl<T> Supertrait for MyType<T> {
|
||||
type Content = T;
|
||||
fn insert(&self, _content: Self::Content) {
|
||||
println!("Inserting content: ");
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> Subtrait for MyType<T> {
|
||||
// MyType::get_content
|
||||
fn get_content(&self) -> Self::Content {
|
||||
(*self).0.clone() // $ fieldof=MyType target=clone target=deref
|
||||
}
|
||||
}
|
||||
|
||||
fn get_content<T: Subtrait>(item: &T) -> T::Content {
|
||||
item.get_content() // $ target=Subtrait::get_content
|
||||
}
|
||||
|
||||
fn insert_three<T: Subtrait2>(item: &T, c1: T::Content, c2: T::Content, c3: T::Content) {
|
||||
item.insert(c1); // $ target=Supertrait::insert
|
||||
item.insert_two(c2, c3); // $ target=Subtrait2::insert_two
|
||||
}
|
||||
|
||||
fn test() {
|
||||
let item1 = MyType(42i64);
|
||||
let _content1 = item1.get_content(); // $ target=MyType::get_content MISSING: type=_content1:i64
|
||||
|
||||
let item2 = MyType(true);
|
||||
let _content2 = get_content(&item2); // $ target=get_content MISSING: type=_content2:bool
|
||||
}
|
||||
}
|
||||
|
||||
mod generic_enum {
|
||||
#[derive(Debug)]
|
||||
enum MyEnum<A> {
|
||||
@@ -1350,23 +1142,6 @@ mod type_aliases {
|
||||
|
||||
type S7<T7> = Result<S6<T7>, S1>;
|
||||
|
||||
struct GenS<GenT>(GenT);
|
||||
|
||||
trait TraitWithAssocType {
|
||||
type Output;
|
||||
fn get_input(self) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<Output> TraitWithAssocType for GenS<Output> {
|
||||
// This is not a recursive type, the `Output` on the right-hand side
|
||||
// refers to the type parameter of the impl block just above.
|
||||
type Output = Result<Output, Output>;
|
||||
|
||||
fn get_input(self) -> Self::Output {
|
||||
Ok(self.0) // $ fieldof=GenS type=Ok(...):Result type=Ok(...):T.Output type=Ok(...):E.Output
|
||||
}
|
||||
}
|
||||
|
||||
pub fn f() {
|
||||
// Type can be inferred from the constructor
|
||||
let p1: MyPair = PairOption::PairBoth(S1, S2);
|
||||
@@ -1387,8 +1162,6 @@ mod type_aliases {
|
||||
g(PairOption::PairSnd(PairOption::PairSnd(S3))); // $ target=g
|
||||
|
||||
let x: S7<S2>; // $ certainType=x:Result $ certainType=x:E.S1 $ certainType=x:T.S4 $ certainType=x:T.T41.S2 $ certainType=x:T.T42.S5 $ certainType=x:T.T42.T5.S2
|
||||
|
||||
let y = GenS(true).get_input(); // $ type=y:Result type=y:T.bool type=y:E.bool target=get_input
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3099,6 +2872,7 @@ mod literal_overlap {
|
||||
}
|
||||
}
|
||||
|
||||
mod associated_types;
|
||||
mod blanket_impl;
|
||||
mod closure;
|
||||
mod dereference;
|
||||
@@ -3112,7 +2886,6 @@ fn main() {
|
||||
method_non_parametric_trait_impl::f(); // $ target=f
|
||||
trait_default_self_type_parameter::test(); // $ target=test
|
||||
function_trait_bounds::f(); // $ target=f
|
||||
associated_type_in_trait::f(); // $ target=f
|
||||
generic_enum::f(); // $ target=f
|
||||
method_supertraits::f(); // $ target=f
|
||||
function_trait_bounds_2::f(); // $ target=f
|
||||
@@ -3133,6 +2906,7 @@ fn main() {
|
||||
method_determined_by_argument_type::f(); // $ target=f
|
||||
tuples::f(); // $ target=f
|
||||
path_buf::f(); // $ target=f
|
||||
associated_types::test(); // $ target=test
|
||||
dereference::test(); // $ target=test
|
||||
pattern_matching::test_all_patterns(); // $ target=test_all_patterns
|
||||
pattern_matching_experimental::box_patterns(); // $ target=box_patterns
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user