Skip to content

Commit f27b5df

Browse files
committed
Unified: Type inference for nested types
1 parent 18b48aa commit f27b5df

20 files changed

Lines changed: 1982 additions & 212 deletions

File tree

‎rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll‎

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2272,7 +2272,11 @@ private module Input3 implements InputSig3 {
22722272
BoolType() { this.getTypeItem() instanceof Builtins::Bool }
22732273
}
22742274

2275-
class AstNode = Rust::AstNode;
2275+
class AstNode extends Rust::AstNode {
2276+
AstNode getParent() { result = this.getParentNode() }
2277+
}
2278+
2279+
AstNode getTypeParameterScope(TypeParameter tp) { result = tp.getDeclaringItem() }
22762280

22772281
final class Expr = ExprImpl;
22782282

@@ -2286,13 +2290,13 @@ private module Input3 implements InputSig3 {
22862290
TypeMention getType() { result = this.getTypeRepr() }
22872291
}
22882292

2289-
class Switch extends Rust::MatchExpr {
2293+
class Switch extends Expr, Rust::MatchExpr {
22902294
Expr getExpr() { result = this.getScrutinee() }
22912295

22922296
Case getCase(int index) { result = this.getArm(index) }
22932297
}
22942298

2295-
class Case extends Rust::MatchArm {
2299+
class Case extends AstNode, Rust::MatchArm {
22962300
AstNode getAPattern() { result = this.getPat() }
22972301

22982302
AstNode getBody() { result = this.getExpr() }
@@ -2453,8 +2457,8 @@ private module Input3 implements InputSig3 {
24532457
// mutual recursion; resolving fields requires resolving types and vice versa
24542458
result =
24552459
[
2456-
resolveStructFieldExpr(this, _).(AstNode),
2457-
resolveTupleFieldExpr(this, _)
2460+
resolveStructFieldExpr(this, _).(Field),
2461+
resolveTupleFieldExpr(this, _).(Field)
24582462
]
24592463
}
24602464
}
@@ -2484,7 +2488,7 @@ private module Input3 implements InputSig3 {
24842488
)
24852489
}
24862490

2487-
class Return extends ReturnExpr {
2491+
class Return extends Expr, ReturnExpr {
24882492
Expr getExpr() { result = super.getExpr() }
24892493
}
24902494

@@ -2587,15 +2591,15 @@ private module Input3 implements InputSig3 {
25872591
override TypeItem getTypeItem() { result = this }
25882592

25892593
override Parameter getParameter(int i) {
2590-
result = [super.getTupleField(i).(AstNode), super.getNthStructField(i)]
2594+
result = [super.getTupleField(i).(Parameter), super.getNthStructField(i).(Parameter)]
25912595
}
25922596
}
25932597

25942598
private class VariantConstructor extends ConstructorImpl instanceof Variant {
25952599
override TypeItem getTypeItem() { result = super.getEnum() }
25962600

25972601
override Parameter getParameter(int i) {
2598-
result = [super.getTupleField(i).(AstNode), super.getNthStructField(i)]
2602+
result = [super.getTupleField(i).(Parameter), super.getNthStructField(i).(Parameter)]
25992603
}
26002604
}
26012605

@@ -3161,7 +3165,7 @@ module Consistency = M3::Consistency;
31613165

31623166
module CachedStage = M3::CachedStage;
31633167

3164-
private predicate typeTestAstNodeRepr(AstNode n, string repr) {
3168+
private predicate typeTestAstNodeRepr(Input3::AstNode n, string repr) {
31653169
repr = [n.toString(), n.(IdentPat).getName().getText()]
31663170
}
31673171

‎shared/typeinference/codeql/typeinference/internal/TypeInference.qll‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2140,13 +2140,24 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
21402140

21412141
/** An AST node. */
21422142
class AstNode {
2143+
/** Gets the parent of this AST node, if any. */
2144+
AstNode getParent();
2145+
21432146
/** Gets a textual representation of this AST node. */
21442147
string toString();
21452148

21462149
/** Gets the location of this AST node. */
21472150
Location getLocation();
21482151
}
21492152

2153+
/**
2154+
* Gets the scope of type parameter `tp`.
2155+
*
2156+
* Only used in a consistency check to ensure that type parameters do not
2157+
* escape their scope.
2158+
*/
2159+
AstNode getTypeParameterScope(TypeParameter tp);
2160+
21502161
/** An expression. */
21512162
class Expr extends AstNode;
21522163

@@ -3754,6 +3765,11 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
37543765
Input3::inferTypeForDefaults(n, path) = t and
37553766
not inferType(n, path) = t
37563767
}
3768+
3769+
query predicate typeParameterEscape(AstNode n, TypePath path, TypeParameter tp) {
3770+
tp = inferType(n, path) and
3771+
not n.getParent*() = getTypeParameterScope(tp)
3772+
}
37573773
}
37583774

37593775
/**

‎unified/ql/lib/codeql/unified/internal/AstExtra.qll‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ module Public {
138138
final class EnumCaseClass extends ClassLikeDeclaration {
139139
EnumCaseClass() { this.hasModifier("enum_case") }
140140

141+
/** Gets the enum declaration that this case class belongs to. */
142+
ClassLikeDeclaration getEnum() { this = result.getAMember() }
143+
141144
/** Gets the constructor of this algebraic data type. */
142145
EnumCaseConstructor getConstructor() { result = this.getAMember() }
143146
}
@@ -168,5 +171,31 @@ module Public {
168171

169172
/** Gets the class containing this constructor. */
170173
EnumCaseClass getEnumCaseClass() { result.getAMember() = this }
174+
175+
/** Gets the enum declaration that this constructor belongs to. */
176+
ClassLikeDeclaration getEnum() { result = this.getEnumCaseClass().getEnum() }
177+
}
178+
179+
/**
180+
* A field of an enum case in an algebraic data type. For example `a` and
181+
* `b` in
182+
*
183+
* ```swift
184+
* enum E {
185+
* case a
186+
* case b
187+
* }
188+
* ```
189+
*/
190+
final class EnumField extends VariableDeclaration {
191+
private ClassLikeDeclaration enum;
192+
193+
EnumField() {
194+
this = enum.getAMember() and
195+
this.hasModifier("enum_case")
196+
}
197+
198+
/** Gets the enum declaration that this enum field belongs to. */
199+
ClassLikeDeclaration getEnum() { result = enum }
171200
}
172201
}

‎unified/ql/lib/codeql/unified/internal/ExprPositions.qll‎

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ private import NameBinding as NameBinding
33
private import ExprPositionsPlugin
44

55
/**
6-
* Holds if `expr` appears in a context where it must refer to a type.
6+
* Holds if `expr` appears in a context where it must refer to a type,
7+
* based entirely on the syntactic context of the expression.
78
*/
8-
predicate isInTypeContext(Expr expr) {
9+
predicate isInSyntacticTypeContext(Expr expr) {
910
expr = any(TypeCastExpr n).getType()
1011
or
1112
expr = any(TypeTestExpr n).getType()
@@ -36,11 +37,24 @@ predicate isInTypeContext(Expr expr) {
3637
or
3738
expr.getParent() instanceof TypeConstraint
3839
or
40+
any(ExprPositionsPlugin p).isInSyntacticTypeContext(expr)
41+
or
42+
isInSyntacticTypeContext(expr.getEnclosingExpr())
43+
}
44+
45+
private predicate isInTypeContext0(Expr expr) {
3946
exists(NameBinding::getTypeFromRef(expr))
4047
or
41-
any(ExprPositionsPlugin p).isInTypeContext(expr)
48+
isInTypeContext0(expr.getEnclosingExpr())
49+
}
50+
51+
/**
52+
* Holds if `expr` appears in a context where it must refer to a type.
53+
*/
54+
predicate isInTypeContext(Expr expr) {
55+
isInSyntacticTypeContext(expr)
4256
or
43-
isInTypeContext(expr.getEnclosingExpr())
57+
isInTypeContext0(expr)
4458
}
4559

4660
/** Holds if `e` appears in a name-binding position inside `declaration` */

‎unified/ql/lib/codeql/unified/internal/ExprPositionsPlugin.qll‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ private module Plugins {
66
}
77

88
class ExprPositionsPlugin extends Unit {
9-
predicate isInTypeContext(Expr e) { none() }
9+
predicate isInSyntacticTypeContext(Expr e) { none() }
1010

1111
predicate isReturnedExpr(Callable callable, Expr e) { none() }
1212
}

‎unified/ql/lib/codeql/unified/internal/ExprPositionsPluginSwift.qll‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ private import unified
22
private import ExprPositionsPlugin
33

44
private class ExprPositionsPluginSwift extends ExprPositionsPlugin {
5-
override predicate isInTypeContext(Expr e) { e = any(GenericTypeExpr g).getBase() }
5+
override predicate isInSyntacticTypeContext(Expr e) { e = any(GenericTypeExpr g).getBase() }
66

77
override predicate isReturnedExpr(Callable callable, Expr e) {
88
// Short-hand return from a function body, e.g. `func foo() -> String { "42" }`

‎unified/ql/lib/codeql/unified/internal/FacadeAst.qll‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ private import unified as U
88
private import AstPlugin
99
private import codeql.files.FileSystem
1010
private import codeql.unified.internal.NameBinding as NameBinding
11+
private import codeql.unified.internal.typeinference.TypeMention as TypeMention
1112

1213
module Unified {
1314
private import Ast::Unified as G
@@ -50,6 +51,11 @@ module Unified {
5051
)
5152
}
5253

54+
/**
55+
* Gets the nearest resolved enclosing class declaration, if any.
56+
*/
57+
ClassLikeDeclaration getEnclosingClassResolved() { result = this.getEnclosingClass().resolve() }
58+
5359
private AstNode overrideEnclosingCallableParent() {
5460
exists(FunctionExpr func |
5561
// Capture declarations are evaluated as part of the outer context, and
@@ -239,15 +245,16 @@ module Unified {
239245
/** Gets the name of this declaration. */
240246
string getName() { result = this.getNameNode().getValue() }
241247

242-
/** Gets a direct base class of this class. */
248+
/** Gets a direct base class of this class, where type aliases are resolved. */
249+
pragma[nomagic]
243250
ClassLikeDeclaration getABaseClass() {
244-
result.getNameNode() =
245-
NameBinding::getStaticBindingTargetFromRef(this.getABaseType().getType())
251+
result = this.getABaseType().getType().(TypeMention::TypeMention).getClassLikeDeclaration()
246252
}
247253

248254
/**
249255
* Gets the target of this extension class, or this class itself if it is not an extension.
250256
*/
257+
pragma[nomagic]
251258
ClassLikeDeclaration resolve() {
252259
not exists(this.getExtensionTarget()) and
253260
result = this

0 commit comments

Comments
 (0)