mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge pull request #19062 from paldepind/rust-ti-1
Rust: Improve handling of trait bounds
This commit is contained in:
@@ -81,6 +81,7 @@ abstract private class StructOrEnumType extends Type {
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets all of the fully parametric `impl` blocks that target this type. */
|
||||
final override ImplMention getABaseTypeMention() {
|
||||
this.asItemNode() = result.resolveSelfTy() and
|
||||
result.isFullyParametric()
|
||||
@@ -153,6 +154,7 @@ class TraitType extends Type, TTrait {
|
||||
result = trait.getTypeBoundList().getABound().getTypeRepr()
|
||||
}
|
||||
|
||||
/** Gets any of the trait bounds of this trait. */
|
||||
override TypeMention getABaseTypeMention() { result = this.getABoundMention() }
|
||||
|
||||
override string toString() { result = trait.toString() }
|
||||
@@ -308,11 +310,19 @@ class TypeParamTypeParameter extends TypeParameter, TTypeParamTypeParameter {
|
||||
|
||||
TypeParam getTypeParam() { result = typeParam }
|
||||
|
||||
override Function getMethod(string name) { result = typeParam.(ItemNode).getASuccessor(name) }
|
||||
override Function getMethod(string name) {
|
||||
// NOTE: If the type parameter has trait bounds, then this finds methods
|
||||
// on the bounding traits.
|
||||
result = typeParam.(ItemNode).getASuccessor(name)
|
||||
}
|
||||
|
||||
override string toString() { result = typeParam.toString() }
|
||||
|
||||
override Location getLocation() { result = typeParam.getLocation() }
|
||||
|
||||
final override TypeMention getABaseTypeMention() {
|
||||
result = typeParam.getTypeBoundList().getABound().getTypeRepr()
|
||||
}
|
||||
}
|
||||
|
||||
/** An implicit reference type parameter. */
|
||||
|
||||
@@ -234,6 +234,10 @@ private Type inferImplicitSelfType(SelfParam self, TypePath path) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets any of the types mentioned in `path` that corresponds to the type
|
||||
* parameter `tp`.
|
||||
*/
|
||||
private TypeMention getExplicitTypeArgMention(Path path, TypeParam tp) {
|
||||
exists(int i |
|
||||
result = path.getPart().getGenericArgList().getTypeArg(pragma[only_bind_into](i)) and
|
||||
|
||||
@@ -36,14 +36,14 @@ mod field_access {
|
||||
let y = GenericThing { a: S };
|
||||
println!("{:?}", x.a);
|
||||
|
||||
// The type of the field `a` can only be infered from the concrete type
|
||||
// The type of the field `a` can only be inferred from the concrete type
|
||||
// in the struct declaration.
|
||||
let x = OptionS {
|
||||
a: MyOption::MyNone(),
|
||||
};
|
||||
println!("{:?}", x.a);
|
||||
|
||||
// The type of the field `a` can only be infered from the type argument
|
||||
// The type of the field `a` can only be inferred from the type argument
|
||||
let x = GenericThing::<MyOption<S>> {
|
||||
a: MyOption::MyNone(),
|
||||
};
|
||||
@@ -191,6 +191,68 @@ mod method_non_parametric_trait_impl {
|
||||
}
|
||||
}
|
||||
|
||||
mod type_parameter_bounds {
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct S1;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct S2;
|
||||
|
||||
// Two traits with the same method name.
|
||||
|
||||
trait FirstTrait<FT> {
|
||||
fn method(self) -> FT;
|
||||
}
|
||||
|
||||
trait SecondTrait<ST> {
|
||||
fn method(self) -> ST;
|
||||
}
|
||||
|
||||
fn call_first_trait_per_bound<I: Debug, T: SecondTrait<I>>(x: T) {
|
||||
// The type parameter bound determines which method this call is resolved to.
|
||||
let s1 = x.method();
|
||||
println!("{:?}", s1);
|
||||
}
|
||||
|
||||
fn call_second_trait_per_bound<I: Debug, T: SecondTrait<I>>(x: T) {
|
||||
// The type parameter bound determines which method this call is resolved to.
|
||||
let s2 = x.method();
|
||||
println!("{:?}", s2);
|
||||
}
|
||||
|
||||
fn trait_bound_with_type<T: FirstTrait<S1>>(x: T) {
|
||||
let s = x.method();
|
||||
println!("{:?}", s);
|
||||
}
|
||||
|
||||
fn trait_per_bound_with_type<T: FirstTrait<S1>>(x: T) {
|
||||
let s = x.method();
|
||||
println!("{:?}", s);
|
||||
}
|
||||
|
||||
trait Pair<P1, P2> {
|
||||
fn fst(self) -> P1;
|
||||
|
||||
fn snd(self) -> P2;
|
||||
}
|
||||
|
||||
fn call_trait_per_bound_with_type_1<T: Pair<S1, S2>>(x: T, y: T) {
|
||||
// The type in the type parameter bound determines the return type.
|
||||
let s1 = x.fst();
|
||||
let s2 = y.snd();
|
||||
println!("{:?}, {:?}", s1, s2);
|
||||
}
|
||||
|
||||
fn call_trait_per_bound_with_type_2<T2: Debug, T: Pair<S1, T2>>(x: T, y: T) {
|
||||
// The type in the type parameter bound determines the return type.
|
||||
let s1 = x.fst();
|
||||
let s2 = y.snd();
|
||||
println!("{:?}, {:?}", s1, s2);
|
||||
}
|
||||
}
|
||||
|
||||
mod function_trait_bounds {
|
||||
#[derive(Debug)]
|
||||
struct MyThing<A> {
|
||||
@@ -443,6 +505,49 @@ mod function_trait_bounds_2 {
|
||||
}
|
||||
}
|
||||
|
||||
mod type_aliases {
|
||||
#[derive(Debug)]
|
||||
enum PairOption<Fst, Snd> {
|
||||
PairNone(),
|
||||
PairFst(Fst),
|
||||
PairSnd(Snd),
|
||||
PairBoth(Fst, Snd),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct S1;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct S2;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct S3;
|
||||
|
||||
// Non-generic type alias that fully applies the generic type
|
||||
type MyPair = PairOption<S1, S2>;
|
||||
|
||||
// Generic type alias that partially applies the generic type
|
||||
type AnotherPair<Thr> = PairOption<S2, Thr>;
|
||||
|
||||
pub fn f() {
|
||||
// Type can be inferred from the constructor
|
||||
let p1: MyPair = PairOption::PairBoth(S1, S2);
|
||||
println!("{:?}", p1);
|
||||
|
||||
// Type can be only inferred from the type alias
|
||||
let p2: MyPair = PairOption::PairNone(); // types for `Fst` and `Snd` missing
|
||||
println!("{:?}", p2);
|
||||
|
||||
// First type from alias, second from constructor
|
||||
let p3: AnotherPair<_> = PairOption::PairSnd(S3); // type for `Fst` missing
|
||||
println!("{:?}", p3);
|
||||
|
||||
// First type from alias definition, second from argument to alias
|
||||
let p3: AnotherPair<S3> = PairOption::PairNone(); // type for `Snd` missing, spurious `S3` for `Fst`
|
||||
println!("{:?}", p3);
|
||||
}
|
||||
}
|
||||
|
||||
mod option_methods {
|
||||
#[derive(Debug)]
|
||||
enum MyOption<T> {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -254,6 +254,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
|
||||
module Make2<InputSig2 Input2> {
|
||||
private import Input2
|
||||
|
||||
/** Gets the type at the empty path of `tm`. */
|
||||
pragma[nomagic]
|
||||
private Type resolveTypeMentionRoot(TypeMention tm) {
|
||||
result = tm.resolveTypeAt(TypePath::nil())
|
||||
@@ -275,7 +276,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
|
||||
*
|
||||
* class Mid<T3> : Base<C<T3>> { }
|
||||
*
|
||||
* class Sub<T4> : Mid<C<T4>> { }
|
||||
* class Sub<T4> : Mid<C<T4>> { } // Sub<T4> extends Base<C<C<T4>>
|
||||
* ```
|
||||
*
|
||||
* - `T3` is mentioned at `0.0` for immediate base type mention `Base<C<T3>>`
|
||||
@@ -334,9 +335,9 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `baseMention` is a (transitive) base type mention of `sub`, and
|
||||
* non-type-parameter `t` is mentioned (implicitly) at `path` inside
|
||||
* `baseMention`. For example, in
|
||||
* Holds if `baseMention` is a (transitive) base type mention of `sub`,
|
||||
* and `t`, which is not a type parameter of `sub`, is mentioned
|
||||
* (implicitly) at `path` inside `baseMention`. For example, in
|
||||
*
|
||||
* ```csharp
|
||||
* class C<T1> { }
|
||||
@@ -345,7 +346,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
|
||||
*
|
||||
* class Mid<T3> : Base<C<T3>> { }
|
||||
*
|
||||
* class Sub<T4> : Mid<C<T4>> { }
|
||||
* class Sub<T4> : Mid<C<T4>> { } // Sub<T4> extends Base<C<C<T4>>
|
||||
* ```
|
||||
*
|
||||
* - ``C`1`` is mentioned at `0` for immediate base type mention `Base<C<T3>>`
|
||||
@@ -359,7 +360,7 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
|
||||
predicate baseTypeMentionHasNonTypeParameterAt(
|
||||
Type sub, TypeMention baseMention, TypePath path, Type t
|
||||
) {
|
||||
not t instanceof TypeParameter and
|
||||
not t = sub.getATypeParameter() and
|
||||
exists(TypeMention immediateBaseMention |
|
||||
pragma[only_bind_into](immediateBaseMention) =
|
||||
getABaseTypeMention(pragma[only_bind_into](sub))
|
||||
|
||||
Reference in New Issue
Block a user