Skip to content

Commit 6002b2d

Browse files
committed
Rust: Improve handling of Self type parameter
1 parent 057db2a commit 6002b2d

File tree

2 files changed

+97
-52
lines changed

2 files changed

+97
-52
lines changed

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

Lines changed: 89 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -151,64 +151,96 @@ 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

165195
/** Gets the type mention in this path for the type parameter `tp`, if any. */
166196
pragma[nomagic]
167-
private TypeMention getTypeMentionForTypeParameter(TypeParameter tp) {
197+
private Type getTypeForTypeParameterAt(TypeParameter tp, TypePath path) {
168198
exists(int i |
169-
result = this.getPositionalTypeArgument(pragma[only_bind_into](i)) and
199+
result = this.getPositionalTypeArgument(pragma[only_bind_into](i), path) and
170200
tp = this.resolveRootType().getPositionalTypeParameter(pragma[only_bind_into](i))
171201
)
172202
or
173-
exists(TypeAlias alias |
174-
result = this.getAnAssocTypeArgument(alias) and
175-
tp = TAssociatedTypeTypeParameter(alias)
176-
)
177-
or
178-
// If `path` is the trait of an `impl` block then any associated types
179-
// defined in the `impl` block are type arguments to the trait.
180-
//
181-
// For instance, for a trait implementation like this
182-
// ```rust
183-
// impl MyTrait for MyType {
184-
// ^^^^^^^ path
185-
// type AssociatedType = i64
186-
// ^^^ result
187-
// // ...
188-
// }
189-
// ```
190-
// the rhs. of the type alias is a type argument to the trait.
191-
exists(ImplItemNode impl, AssociatedTypeTypeParameter param, TypeAlias alias, string name |
192-
this = impl.getTraitPath() and
193-
param.getTrait() = resolved and
194-
name = param.getTypeAlias().getName().getText() and
195-
alias = impl.getASuccessor(pragma[only_bind_into](name)) and
196-
result = alias.getTypeRepr() and
197-
tp =
198-
TAssociatedTypeTypeParameter(resolved
199-
.(TraitItemNode)
200-
.getAssocItem(pragma[only_bind_into](name)))
201-
)
202-
or
203-
// Handle the special syntactic sugar for function traits. For now we only
204-
// support `FnOnce` as we can't support the "inherited" associated types of
205-
// `Fn` and `FnMut` yet.
206-
exists(FnOnceTrait t | t = resolved |
207-
tp = TTypeParamTypeParameter(t.getTypeParam()) and
208-
result = this.getSegment().getParenthesizedArgList()
203+
exists(TypeMention tm | result = tm.resolveTypeAt(path) |
204+
exists(TypeAlias alias |
205+
tm = this.getAnAssocTypeArgument(alias) and
206+
tp = TAssociatedTypeTypeParameter(alias)
207+
)
208+
or
209+
// If `path` is the trait of an `impl` block then any associated types
210+
// defined in the `impl` block are type arguments to the trait.
211+
//
212+
// For instance, for a trait implementation like this
213+
// ```rust
214+
// impl MyTrait for MyType {
215+
// ^^^^^^^ path
216+
// type AssociatedType = i64
217+
// ^^^ tm
218+
// // ...
219+
// }
220+
// ```
221+
// the rhs. of the type alias is a type argument to the trait.
222+
exists(ImplItemNode impl, AssociatedTypeTypeParameter param, TypeAlias alias, string name |
223+
this = impl.getTraitPath() and
224+
param.getTrait() = resolved and
225+
name = param.getTypeAlias().getName().getText() and
226+
alias = impl.getASuccessor(pragma[only_bind_into](name)) and
227+
tm = alias.getTypeRepr() and
228+
tp =
229+
TAssociatedTypeTypeParameter(resolved
230+
.(TraitItemNode)
231+
.getAssocItem(pragma[only_bind_into](name)))
232+
)
209233
or
210-
tp = TAssociatedTypeTypeParameter(t.getOutputType()) and
211-
result = this.getSegment().getRetType().getTypeRepr()
234+
// Handle the special syntactic sugar for function traits. For now we only
235+
// support `FnOnce` as we can't support the "inherited" associated types of
236+
// `Fn` and `FnMut` yet.
237+
exists(FnOnceTrait t | t = resolved |
238+
tp = TTypeParamTypeParameter(t.getTypeParam()) and
239+
tm = this.getSegment().getParenthesizedArgList()
240+
or
241+
tp = TAssociatedTypeTypeParameter(t.getOutputType()) and
242+
tm = this.getSegment().getRetType().getTypeRepr()
243+
)
212244
)
213245
}
214246

@@ -238,9 +270,16 @@ class NonAliasPathTypeMention extends PathTypeMention {
238270
result = this.resolveRootType()
239271
or
240272
exists(TypeParameter tp, TypePath suffix |
241-
result = this.getTypeMentionForTypeParameter(tp).resolveTypeAt(suffix) and
273+
result = this.getTypeForTypeParameterAt(tp, suffix) and
242274
typePath = TypePath::cons(tp, suffix)
243275
)
276+
or
277+
// When the path refers to a trait, then the implicit `Self` type parameter
278+
// should be instantiated from the context.
279+
exists(TypePath suffix |
280+
result = this.getSelfTypeParameter().resolveTypeAt(suffix) and
281+
typePath = TypePath::cons(TSelfTypeParameter(resolved), suffix)
282+
)
244283
}
245284
}
246285

@@ -296,6 +335,11 @@ class TraitMention extends TypeMention instanceof TraitItemNode {
296335
typePath.isEmpty() and
297336
result = TTrait(this)
298337
or
338+
// The implicit `Self` type parameter occurs at the `Self` type parameter
339+
// position.
340+
typePath = TypePath::singleton(TSelfTypeParameter(this)) and
341+
result = TSelfTypeParameter(this)
342+
or
299343
exists(TypeAlias alias |
300344
alias = super.getAnAssocItem() and
301345
typePath = TypePath::singleton(result) and

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

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2013,18 +2013,18 @@ inferType
20132013
| main.rs:667:44:667:48 | thing | | main.rs:667:24:667:41 | T |
20142014
| main.rs:667:61:670:5 | { ... } | | {EXTERNAL LOCATION} | i64 |
20152015
| main.rs:668:13:668:18 | also_t | | {EXTERNAL LOCATION} | Option |
2016-
| main.rs:668:13:668:18 | also_t | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
2016+
| main.rs:668:13:668:18 | also_t | T | main.rs:667:24:667:41 | T |
20172017
| main.rs:668:22:668:26 | thing | | main.rs:667:24:667:41 | T |
20182018
| main.rs:668:22:668:34 | thing.get_a() | | {EXTERNAL LOCATION} | Option |
2019-
| main.rs:668:22:668:34 | thing.get_a() | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
2019+
| main.rs:668:22:668:34 | thing.get_a() | T | main.rs:667:24:667:41 | T |
20202020
| main.rs:669:9:669:9 | 0 | | {EXTERNAL LOCATION} | i32 |
20212021
| main.rs:669:9:669:9 | 0 | | {EXTERNAL LOCATION} | i64 |
20222022
| main.rs:674:55:674:59 | thing | | file://:0:0:0:0 | & |
20232023
| main.rs:674:55:674:59 | thing | &T | main.rs:674:25:674:52 | T |
20242024
| main.rs:675:13:675:19 | _also_t | | {EXTERNAL LOCATION} | Option |
2025-
| main.rs:675:13:675:19 | _also_t | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
2025+
| main.rs:675:13:675:19 | _also_t | T | main.rs:674:25:674:52 | T |
20262026
| main.rs:675:23:675:34 | get_a(...) | | {EXTERNAL LOCATION} | Option |
2027-
| main.rs:675:23:675:34 | get_a(...) | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
2027+
| main.rs:675:23:675:34 | get_a(...) | T | main.rs:674:25:674:52 | T |
20282028
| main.rs:675:29:675:33 | thing | | file://:0:0:0:0 | & |
20292029
| main.rs:675:29:675:33 | thing | &T | main.rs:674:25:674:52 | T |
20302030
| main.rs:683:18:683:22 | SelfParam | | file://:0:0:0:0 | & |
@@ -2041,9 +2041,9 @@ inferType
20412041
| main.rs:691:17:691:37 | MyStruct {...} | | main.rs:678:5:680:5 | MyStruct |
20422042
| main.rs:691:35:691:35 | 0 | | {EXTERNAL LOCATION} | i32 |
20432043
| main.rs:692:13:692:14 | _a | | {EXTERNAL LOCATION} | Option |
2044-
| main.rs:692:13:692:14 | _a | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
2044+
| main.rs:692:13:692:14 | _a | T | main.rs:678:5:680:5 | MyStruct |
20452045
| main.rs:692:18:692:26 | get_a(...) | | {EXTERNAL LOCATION} | Option |
2046-
| main.rs:692:18:692:26 | get_a(...) | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
2046+
| main.rs:692:18:692:26 | get_a(...) | T | main.rs:678:5:680:5 | MyStruct |
20472047
| main.rs:692:24:692:25 | &s | | file://:0:0:0:0 | & |
20482048
| main.rs:692:24:692:25 | &s | &T | main.rs:678:5:680:5 | MyStruct |
20492049
| main.rs:692:25:692:25 | s | | main.rs:678:5:680:5 | MyStruct |
@@ -4776,7 +4776,6 @@ inferType
47764776
| main.rs:2308:16:2308:21 | self.0 | | main.rs:2303:10:2303:17 | T |
47774777
| main.rs:2308:31:2308:35 | other | | main.rs:2301:5:2301:19 | S |
47784778
| main.rs:2308:31:2308:35 | other | T | main.rs:2303:10:2303:17 | T |
4779-
| main.rs:2308:31:2308:37 | other.0 | | main.rs:2263:5:2268:5 | Self [trait MyAdd] |
47804779
| main.rs:2308:31:2308:37 | other.0 | | main.rs:2303:10:2303:17 | T |
47814780
| main.rs:2316:19:2316:22 | SelfParam | | main.rs:2301:5:2301:19 | S |
47824781
| main.rs:2316:19:2316:22 | SelfParam | T | main.rs:2312:10:2312:17 | T |
@@ -7447,3 +7446,5 @@ inferType
74477446
| pattern_matching.rs:827:5:827:7 | f(...) | | {EXTERNAL LOCATION} | Option |
74487447
| pattern_matching.rs:827:5:827:7 | f(...) | T | file://:0:0:0:0 | () |
74497448
testFailures
7449+
| main.rs:675:13:675:19 | _also_t | Fixed missing result: type=_also_t:T.T |
7450+
| main.rs:692:13:692:14 | _a | Fixed missing result: type=_a:T.MyStruct |

0 commit comments

Comments
 (0)