Merge pull request #19756 from paldepind/rust/type-parameters-default

Rust: Type inference uses defaults for type parameters
This commit is contained in:
Simon Friis Vindum
2025-06-16 10:53:14 +02:00
committed by GitHub
5 changed files with 2717 additions and 2640 deletions

View File

@@ -42,6 +42,9 @@ abstract class Type extends TType {
/** Gets the `i`th type parameter of this type, if any. */
abstract TypeParameter getTypeParameter(int i);
/** Gets the default type for the `i`th type parameter, if any. */
TypeMention getTypeParameterDefault(int i) { none() }
/** Gets a type parameter of this type. */
final TypeParameter getATypeParameter() { result = this.getTypeParameter(_) }
@@ -87,6 +90,10 @@ class StructType extends StructOrEnumType, TStruct {
result = TTypeParamTypeParameter(struct.getGenericParamList().getTypeParam(i))
}
override TypeMention getTypeParameterDefault(int i) {
result = struct.getGenericParamList().getTypeParam(i).getDefaultType()
}
override string toString() { result = struct.getName().getText() }
override Location getLocation() { result = struct.getLocation() }
@@ -108,6 +115,10 @@ class EnumType extends StructOrEnumType, TEnum {
result = TTypeParamTypeParameter(enum.getGenericParamList().getTypeParam(i))
}
override TypeMention getTypeParameterDefault(int i) {
result = enum.getGenericParamList().getTypeParam(i).getDefaultType()
}
override string toString() { result = enum.getName().getText() }
override Location getLocation() { result = enum.getLocation() }
@@ -133,6 +144,10 @@ class TraitType extends Type, TTrait {
any(AssociatedTypeTypeParameter param | param.getTrait() = trait and param.getIndex() = i)
}
override TypeMention getTypeParameterDefault(int i) {
result = trait.getGenericParamList().getTypeParam(i).getDefaultType()
}
override string toString() { result = trait.toString() }
override Location getLocation() { result = trait.getLocation() }

View File

@@ -1594,6 +1594,11 @@ private module Debug {
result = resolveMethodCallTarget(mce)
}
predicate debugTypeMention(TypeMention tm, TypePath path, Type type) {
tm = getRelevantLocatable() and
tm.resolveTypeAt(path) = type
}
pragma[nomagic]
private int countTypes(AstNode n, TypePath path, Type t) {
t = inferType(n, path) and

View File

@@ -88,6 +88,11 @@ class PathTypeReprMention extends TypeMention instanceof PathTypeRepr {
override TypeMention getTypeArgument(int i) {
result = path.getSegment().getGenericArgList().getTypeArg(i)
or
// If a type argument is not given in the path, then we use the default for
// the type parameter if one exists for the type.
not exists(path.getSegment().getGenericArgList().getTypeArg(i)) and
result = this.resolveType().getTypeParameterDefault(i)
or
// `Self` paths inside `impl` blocks have implicit type arguments that are
// the type parameters of the `impl` block. For example, in
//

View File

@@ -14,7 +14,7 @@ mod field_access {
}
#[derive(Debug)]
struct GenericThing<A> {
struct GenericThing<A = bool> {
a: A,
}
@@ -27,6 +27,11 @@ mod field_access {
println!("{:?}", x.a); // $ fieldof=MyThing
}
fn default_field_access(x: GenericThing) {
let a = x.a; // $ fieldof=GenericThing type=a:bool
println!("{:?}", a);
}
fn generic_field_access() {
// Explicit type argument
let x = GenericThing::<S> { a: S }; // $ type=x:A.S
@@ -472,7 +477,7 @@ mod type_parameter_bounds {
println!("{:?}", s); // $ type=s:S1
}
trait Pair<P1, P2> {
trait Pair<P1 = bool, P2 = i64> {
fn fst(self) -> P1;
fn snd(self) -> P2;
@@ -480,8 +485,8 @@ mod type_parameter_bounds {
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(); // $ method=fst
let s2 = y.snd(); // $ method=snd
let s1 = x.fst(); // $ method=fst type=s1:S1
let s2 = y.snd(); // $ method=snd type=s2:S2
println!("{:?}, {:?}", s1, s2);
}
@@ -491,6 +496,20 @@ mod type_parameter_bounds {
let s2 = y.snd(); // $ method=snd
println!("{:?}, {:?}", s1, s2);
}
fn call_trait_per_bound_with_type_3<T: Pair>(x: T, y: T) {
// The type in the type parameter bound determines the return type.
let s1 = x.fst(); // $ method=fst type=s1:bool
let s2 = y.snd(); // $ method=snd type=s2:i64
println!("{:?}, {:?}", s1, s2);
}
fn call_trait_per_bound_with_type_4<T: Pair<u8>>(x: T, y: T) {
// The type in the type parameter bound determines the return type.
let s1 = x.fst(); // $ method=fst type=s1:u8
let s2 = y.snd(); // $ method=snd type=s2:i64
println!("{:?}, {:?}", s1, s2);
}
}
mod function_trait_bounds {