Skip to content

Commit ad5c5ac

Browse files
authored
Merge pull request #20094 from paldepind/rust/type-inference-path-mention
Rust: Refactor `PathTypeMention`
2 parents 472a6b5 + 441cefd commit ad5c5ac

File tree

2 files changed

+113
-86
lines changed

2 files changed

+113
-86
lines changed

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

Lines changed: 113 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -50,24 +50,70 @@ class SliceTypeReprMention extends TypeMention instanceof SliceTypeRepr {
5050
}
5151
}
5252

53-
class PathTypeMention extends TypeMention, Path {
54-
TypeItemNode resolved;
53+
/** Holds if `path` is used as a type mention during type inference. */
54+
predicate relevantPathTypeMention(Path path) {
55+
path =
56+
[
57+
any(PathTypeRepr r).getPath(),
58+
any(StructExpr s).getPath().getQualifier*(),
59+
any(CallExpr ce).getFunction().(PathExpr).getPath().getQualifier*(),
60+
any(StructPat p).getPath(),
61+
any(TupleStructPat p).getPath()
62+
]
63+
}
64+
65+
abstract class PathTypeMention extends TypeMention, Path {
66+
PathTypeMention() { relevantPathTypeMention(this) }
67+
}
68+
69+
class AliasPathTypeMention extends PathTypeMention {
70+
TypeAlias resolved;
71+
TypeMention rhs;
72+
73+
AliasPathTypeMention() {
74+
resolved = resolvePath(this) and
75+
rhs = resolved.getTypeRepr()
76+
}
77+
78+
TypeItemNode getResolved() { result = resolved }
5579

56-
PathTypeMention() {
57-
resolved = resolvePath(this)
80+
/**
81+
* Holds if this path resolved to a type alias with a rhs. that has the
82+
* resulting type at `typePath`.
83+
*/
84+
pragma[nomagic]
85+
override Type resolveTypeAt(TypePath typePath) {
86+
result = rhs.resolveTypeAt(typePath) and
87+
not result = pathGetTypeParameter(resolved, _)
5888
or
59-
resolved = resolvePath(this).(Variant).getEnum()
89+
exists(TypeParameter tp, TypeMention arg, TypePath prefix, TypePath suffix, int i |
90+
tp = rhs.resolveTypeAt(prefix) and
91+
tp = pathGetTypeParameter(resolved, pragma[only_bind_into](i)) and
92+
arg = this.getSegment().getGenericArgList().getTypeArg(pragma[only_bind_into](i)) and
93+
result = arg.resolveTypeAt(suffix) and
94+
typePath = prefix.append(suffix)
95+
)
96+
}
97+
}
98+
99+
class NonAliasPathTypeMention extends PathTypeMention {
100+
TypeItemNode resolved;
101+
102+
NonAliasPathTypeMention() {
103+
resolved = [resolvePath(this), resolvePath(this).(Variant).getEnum().(TypeItemNode)] and
104+
not exists(resolved.(TypeAlias).getTypeRepr())
60105
}
61106

62107
TypeItemNode getResolved() { result = resolved }
63108

109+
/**
110+
* Gets a type alias with the name `name` of the trait that this path resolves
111+
* to, if any.
112+
*/
64113
pragma[nomagic]
65114
private TypeAlias getResolvedTraitAlias(string name) {
66-
exists(TraitItemNode trait |
67-
trait = resolved and
68-
result = trait.getAnAssocItem() and
69-
name = result.getName().getText()
70-
)
115+
result = resolved.(TraitItemNode).getAnAssocItem() and
116+
name = result.getName().getText()
71117
}
72118

73119
pragma[nomagic]
@@ -115,92 +161,75 @@ class PathTypeMention extends TypeMention, Path {
115161
// If a type argument is not given in the path, then we use the default for
116162
// the type parameter if one exists for the type.
117163
not exists(this.getPositionalTypeArgument0(i)) and
118-
result = this.resolveType().getTypeParameterDefault(i) and
164+
result = this.resolveRootType().getTypeParameterDefault(i) and
119165
// Defaults only apply to type mentions in type annotations
120166
this = any(PathTypeRepr ptp).getPath().getQualifier*()
121167
}
122168

123-
/**
124-
* Holds if this path resolved to a type alias with a rhs. that has the
125-
* resulting type at `typePath`.
126-
*/
169+
/** Gets the type mention in this path for the type parameter `tp`, if any. */
127170
pragma[nomagic]
128-
private Type aliasResolveTypeAt(TypePath typePath) {
129-
exists(TypeAlias alias, TypeMention rhs | alias = resolved and rhs = alias.getTypeRepr() |
130-
result = rhs.resolveTypeAt(typePath) and
131-
not result = pathGetTypeParameter(alias, _)
132-
or
133-
exists(TypeParameter tp, TypeMention arg, TypePath prefix, TypePath suffix, int i |
134-
tp = rhs.resolveTypeAt(prefix) and
135-
tp = pathGetTypeParameter(alias, pragma[only_bind_into](i)) and
136-
arg = this.getSegment().getGenericArgList().getTypeArg(pragma[only_bind_into](i)) and
137-
result = arg.resolveTypeAt(suffix) and
138-
typePath = prefix.append(suffix)
139-
)
171+
private TypeMention getTypeMentionForTypeParameter(TypeParameter tp) {
172+
exists(int i |
173+
result = this.getPositionalTypeArgument(pragma[only_bind_into](i)) and
174+
tp = this.resolveRootType().getTypeParameter(pragma[only_bind_into](i))
175+
)
176+
or
177+
exists(TypeAlias alias |
178+
result = this.getAnAssocTypeArgument(alias) and
179+
tp = TAssociatedTypeTypeParameter(alias)
180+
)
181+
or
182+
// If `path` is the trait of an `impl` block then any associated types
183+
// defined in the `impl` block are type arguments to the trait.
184+
//
185+
// For instance, for a trait implementation like this
186+
// ```rust
187+
// impl MyTrait for MyType {
188+
// ^^^^^^^ path
189+
// type AssociatedType = i64
190+
// ^^^ result
191+
// // ...
192+
// }
193+
// ```
194+
// the rhs. of the type alias is a type argument to the trait.
195+
exists(ImplItemNode impl, AssociatedTypeTypeParameter param, TypeAlias alias, string name |
196+
this = impl.getTraitPath() and
197+
param.getTrait() = resolved and
198+
name = param.getTypeAlias().getName().getText() and
199+
alias = impl.getASuccessor(pragma[only_bind_into](name)) and
200+
result = alias.getTypeRepr() and
201+
tp =
202+
TAssociatedTypeTypeParameter(resolved
203+
.(TraitItemNode)
204+
.getAssocItem(pragma[only_bind_into](name)))
140205
)
141206
}
142207

143-
override Type resolveTypeAt(TypePath typePath) {
144-
result = this.aliasResolveTypeAt(typePath)
208+
Type resolveRootType() {
209+
result = TStruct(resolved)
145210
or
146-
typePath.isEmpty() and
147-
(
148-
result = TStruct(resolved)
149-
or
150-
result = TEnum(resolved)
151-
or
152-
exists(TraitItemNode trait | trait = resolved |
153-
// If this is a `Self` path, then it resolves to the implicit `Self`
154-
// type parameter, otherwise it is a trait bound.
155-
if this = trait.getASelfPath()
156-
then result = TSelfTypeParameter(trait)
157-
else result = TTrait(trait)
158-
)
159-
or
160-
result = TTypeParamTypeParameter(resolved)
161-
or
162-
result = TAssociatedTypeTypeParameter(resolved)
211+
result = TEnum(resolved)
212+
or
213+
exists(TraitItemNode trait | trait = resolved |
214+
// If this is a `Self` path, then it resolves to the implicit `Self`
215+
// type parameter, otherwise it is a trait bound.
216+
if this = trait.getASelfPath()
217+
then result = TSelfTypeParameter(trait)
218+
else result = TTrait(trait)
163219
)
164220
or
165-
not exists(resolved.(TypeAlias).getTypeRepr()) and
166-
exists(TypeParameter tp, TypeMention arg, TypePath suffix |
167-
result = arg.resolveTypeAt(suffix) and
221+
result = TTypeParamTypeParameter(resolved)
222+
or
223+
result = TAssociatedTypeTypeParameter(resolved)
224+
}
225+
226+
override Type resolveTypeAt(TypePath typePath) {
227+
typePath.isEmpty() and
228+
result = this.resolveRootType()
229+
or
230+
exists(TypeParameter tp, TypePath suffix |
231+
result = this.getTypeMentionForTypeParameter(tp).resolveTypeAt(suffix) and
168232
typePath = TypePath::cons(tp, suffix)
169-
|
170-
exists(int i |
171-
arg = this.getPositionalTypeArgument(pragma[only_bind_into](i)) and
172-
tp = this.resolveType().getTypeParameter(pragma[only_bind_into](i))
173-
)
174-
or
175-
exists(TypeAlias alias |
176-
arg = this.getAnAssocTypeArgument(alias) and
177-
tp = TAssociatedTypeTypeParameter(alias)
178-
)
179-
or
180-
// If `path` is the trait of an `impl` block then any associated types
181-
// defined in the `impl` block are type arguments to the trait.
182-
//
183-
// For instance, for a trait implementation like this
184-
// ```rust
185-
// impl MyTrait for MyType {
186-
// ^^^^^^^ path
187-
// type AssociatedType = i64
188-
// ^^^ result
189-
// // ...
190-
// }
191-
// ```
192-
// the rhs. of the type alias is a type argument to the trait.
193-
exists(ImplItemNode impl, AssociatedTypeTypeParameter param, TypeAlias alias, string name |
194-
this = impl.getTraitPath() and
195-
param.getTrait() = resolved and
196-
name = param.getTypeAlias().getName().getText() and
197-
alias = impl.getASuccessor(pragma[only_bind_into](name)) and
198-
arg = alias.getTypeRepr() and
199-
tp =
200-
TAssociatedTypeTypeParameter(resolved
201-
.(TraitItemNode)
202-
.getAssocItem(pragma[only_bind_into](name)))
203-
)
204233
)
205234
}
206235
}

rust/ql/test/query-tests/unusedentities/CONSISTENCY/TypeInferenceConsistency.expected

Lines changed: 0 additions & 2 deletions
This file was deleted.

0 commit comments

Comments
 (0)