Skip to content

Commit 9022f99

Browse files
committed
Rust: Improve handling of occurrences of the Self type parameter
1 parent 9ff3c61 commit 9022f99

File tree

3 files changed

+70
-22
lines changed

3 files changed

+70
-22
lines changed

rust/ql/lib/codeql/rust/internal/TypeMention.qll

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -151,25 +151,61 @@ class NonAliasPathTypeMention extends PathTypeMention {
151151
result = this.getQualifier().getSegment().getGenericArgList().getTypeArg(i)
152152
}
153153

154-
private TypeMention getPositionalTypeArgument(int i) {
155-
result = this.getPositionalTypeArgument0(i)
154+
/**
155+
* Gets the type mention that instantiates the implicit `Self` type parameter
156+
* for this path, if it occurs in the position of a trait bound.
157+
*/
158+
private TypeMention getSelfTypeParameter() {
159+
exists(ImplItemNode impl | this = impl.getTraitPath() and result = impl.(Impl).getSelfTy())
160+
or
161+
exists(Trait subTrait |
162+
this = subTrait.getATypeBound().getTypeRepr().(PathTypeRepr).getPath() and
163+
result.(SelfTypeParameterMention).getTrait() = subTrait
164+
)
165+
or
166+
exists(TypeParamItemNode tp | this = tp.getABoundPath() and result = tp)
167+
}
168+
169+
private Type getPositionalTypeArgument(int i, TypePath path) {
170+
result = this.getPositionalTypeArgument0(i).resolveTypeAt(path)
156171
or
172+
result = this.getDefaultPositionalTypeArgument(i, path)
173+
}
174+
175+
private Type getDefaultPositionalTypeArgument(int i, TypePath path) {
157176
// If a type argument is not given in the path, then we use the default for
158177
// the type parameter if one exists for the type.
159178
not exists(this.getPositionalTypeArgument0(i)) and
160-
result = this.resolveRootType().getTypeParameterDefault(i) and
161179
// Defaults only apply to type mentions in type annotations
162-
this = any(PathTypeRepr ptp).getPath().getQualifier*()
180+
this = any(PathTypeRepr ptp).getPath().getQualifier*() and
181+
exists(Type ty, TypePath prefix |
182+
ty = this.resolveRootType().getTypeParameterDefault(i).resolveTypeAt(prefix) and
183+
if not ty = TSelfTypeParameter(resolved)
184+
then result = ty and path = prefix
185+
else
186+
// When a default contains an implicit `Self` type parameter, it should
187+
// be substituted for the type that implements the trait.
188+
exists(TypePath suffix |
189+
path = prefix.append(suffix) and
190+
result = this.getSelfTypeParameter().resolveTypeAt(suffix)
191+
)
192+
)
163193
}
164194

165-
/** Gets the type mention in this path for the type parameter `tp`, if any. */
166-
pragma[nomagic]
167-
private TypeMention getTypeMentionForTypeParameter(TypeParameter tp) {
195+
/**
196+
* Gets the type for this path for the type parameter `tp` at `path`, when the
197+
* type parameter does not correspond directly to a type mention.
198+
*/
199+
private Type getTypeForTypeParameterAt(TypeParameter tp, TypePath path) {
168200
exists(int i |
169-
result = this.getPositionalTypeArgument(pragma[only_bind_into](i)) and
201+
result = this.getPositionalTypeArgument(pragma[only_bind_into](i), path) and
170202
tp = this.resolveRootType().getPositionalTypeParameter(pragma[only_bind_into](i))
171203
)
172-
or
204+
}
205+
206+
/** Gets the type mention in this path for the type parameter `tp`, if any. */
207+
pragma[nomagic]
208+
private TypeMention getTypeMentionForTypeParameter(TypeParameter tp) {
173209
exists(TypeAlias alias |
174210
result = this.getAnAssocTypeArgument(alias) and
175211
tp = TAssociatedTypeTypeParameter(alias)
@@ -237,9 +273,17 @@ class NonAliasPathTypeMention extends PathTypeMention {
237273
typePath.isEmpty() and
238274
result = this.resolveRootType()
239275
or
240-
exists(TypeParameter tp, TypePath suffix |
241-
result = this.getTypeMentionForTypeParameter(tp).resolveTypeAt(suffix) and
242-
typePath = TypePath::cons(tp, suffix)
276+
exists(TypeParameter tp, TypePath suffix | typePath = TypePath::cons(tp, suffix) |
277+
result = this.getTypeForTypeParameterAt(tp, suffix)
278+
or
279+
result = this.getTypeMentionForTypeParameter(tp).resolveTypeAt(suffix)
280+
)
281+
or
282+
// When the path refers to a trait, then the implicit `Self` type parameter
283+
// should be instantiated from the context.
284+
exists(TypePath suffix |
285+
result = this.getSelfTypeParameter().resolveTypeAt(suffix) and
286+
typePath = TypePath::cons(TSelfTypeParameter(resolved), suffix)
243287
)
244288
}
245289
}
@@ -296,6 +340,11 @@ class TraitMention extends TypeMention instanceof TraitItemNode {
296340
typePath.isEmpty() and
297341
result = TTrait(this)
298342
or
343+
// The implicit `Self` type parameter occurs at the `Self` type parameter
344+
// position.
345+
typePath = TypePath::singleton(TSelfTypeParameter(this)) and
346+
result = TSelfTypeParameter(this)
347+
or
299348
exists(TypeAlias alias |
300349
alias = super.getAnAssocItem() and
301350
typePath = TypePath::singleton(result) and

rust/ql/test/library-tests/type-inference/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -666,7 +666,7 @@ mod trait_default_self_type_parameter {
666666

667667
// The trait bound on `T` uses the default for `A` which contains `Self`
668668
fn tp_uses_default<S: TraitWithSelfTp>(thing: S) -> i64 {
669-
let _ms = thing.get_a(); // $ target=TraitWithSelfTp::get_a MISSING: type=_ms:T.S
669+
let _ms = thing.get_a(); // $ target=TraitWithSelfTp::get_a type=_ms:T.S
670670
0
671671
}
672672

@@ -675,7 +675,7 @@ mod trait_default_self_type_parameter {
675675

676676
fn get_a_through_tp<S: SubTraitOfTraitWithSelfTp>(thing: &S) {
677677
// `thing` is a `TraitWithSelfTp` through the trait hierarchy
678-
let _ms = get_a(thing); // $ target=get_a MISSING: type=_ms:T.S
678+
let _ms = get_a(thing); // $ target=get_a type=_ms:T.S
679679
}
680680

681681
struct MyStruct {
@@ -693,7 +693,7 @@ mod trait_default_self_type_parameter {
693693

694694
pub fn test() {
695695
let s = MyStruct { value: 0 };
696-
let _ms = get_a(&s); // $ target=get_a MISSING: type=_ms:T.MyStruct
696+
let _ms = get_a(&s); // $ target=get_a type=_ms:T.MyStruct
697697
}
698698
}
699699

rust/ql/test/library-tests/type-inference/type-inference.expected

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2013,18 +2013,18 @@ inferType
20132013
| main.rs:668:44:668:48 | thing | | main.rs:668:24:668:41 | S |
20142014
| main.rs:668:61:671:5 | { ... } | | {EXTERNAL LOCATION} | i64 |
20152015
| main.rs:669:13:669:15 | _ms | | {EXTERNAL LOCATION} | Option |
2016-
| main.rs:669:13:669:15 | _ms | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
2016+
| main.rs:669:13:669:15 | _ms | T | main.rs:668:24:668:41 | S |
20172017
| main.rs:669:19:669:23 | thing | | main.rs:668:24:668:41 | S |
20182018
| main.rs:669:19:669:31 | thing.get_a() | | {EXTERNAL LOCATION} | Option |
2019-
| main.rs:669:19:669:31 | thing.get_a() | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
2019+
| main.rs:669:19:669:31 | thing.get_a() | T | main.rs:668:24:668:41 | S |
20202020
| main.rs:670:9:670:9 | 0 | | {EXTERNAL LOCATION} | i32 |
20212021
| main.rs:670:9:670:9 | 0 | | {EXTERNAL LOCATION} | i64 |
20222022
| main.rs:676:55:676:59 | thing | | file://:0:0:0:0 | & |
20232023
| main.rs:676:55:676:59 | thing | &T | main.rs:676:25:676:52 | S |
20242024
| main.rs:678:13:678:15 | _ms | | {EXTERNAL LOCATION} | Option |
2025-
| main.rs:678:13:678:15 | _ms | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
2025+
| main.rs:678:13:678:15 | _ms | T | main.rs:676:25:676:52 | S |
20262026
| main.rs:678:19:678:30 | get_a(...) | | {EXTERNAL LOCATION} | Option |
2027-
| main.rs:678:19:678:30 | get_a(...) | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
2027+
| main.rs:678:19:678:30 | get_a(...) | T | main.rs:676:25:676:52 | S |
20282028
| main.rs:678:25:678:29 | thing | | file://:0:0:0:0 | & |
20292029
| main.rs:678:25:678:29 | thing | &T | main.rs:676:25:676:52 | S |
20302030
| main.rs:687:18:687:22 | SelfParam | | file://:0:0:0:0 | & |
@@ -2041,9 +2041,9 @@ inferType
20412041
| main.rs:695:17:695:37 | MyStruct {...} | | main.rs:681:5:683:5 | MyStruct |
20422042
| main.rs:695:35:695:35 | 0 | | {EXTERNAL LOCATION} | i32 |
20432043
| main.rs:696:13:696:15 | _ms | | {EXTERNAL LOCATION} | Option |
2044-
| main.rs:696:13:696:15 | _ms | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
2044+
| main.rs:696:13:696:15 | _ms | T | main.rs:681:5:683:5 | MyStruct |
20452045
| main.rs:696:19:696:27 | get_a(...) | | {EXTERNAL LOCATION} | Option |
2046-
| main.rs:696:19:696:27 | get_a(...) | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
2046+
| main.rs:696:19:696:27 | get_a(...) | T | main.rs:681:5:683:5 | MyStruct |
20472047
| main.rs:696:25:696:26 | &s | | file://:0:0:0:0 | & |
20482048
| main.rs:696:25:696:26 | &s | &T | main.rs:681:5:683:5 | MyStruct |
20492049
| main.rs:696:26:696:26 | s | | main.rs:681:5:683:5 | MyStruct |
@@ -4776,7 +4776,6 @@ inferType
47764776
| main.rs:2312:16:2312:21 | self.0 | | main.rs:2307:10:2307:17 | T |
47774777
| main.rs:2312:31:2312:35 | other | | main.rs:2305:5:2305:19 | S |
47784778
| main.rs:2312:31:2312:35 | other | T | main.rs:2307:10:2307:17 | T |
4779-
| main.rs:2312:31:2312:37 | other.0 | | main.rs:2267:5:2272:5 | Self [trait MyAdd] |
47804779
| main.rs:2312:31:2312:37 | other.0 | | main.rs:2307:10:2307:17 | T |
47814780
| main.rs:2320:19:2320:22 | SelfParam | | main.rs:2305:5:2305:19 | S |
47824781
| main.rs:2320:19:2320:22 | SelfParam | T | main.rs:2316:10:2316:17 | T |

0 commit comments

Comments
 (0)