Skip to content

Commit c84a964

Browse files
committed
Rust: Address review comments and handle ! types in type inference
1 parent 5697a7e commit c84a964

File tree

6 files changed

+107
-30
lines changed

6 files changed

+107
-30
lines changed

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

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,17 @@ private Type inferAnnotatedType(AstNode n, TypePath path) {
291291
result = n.(ShorthandSelfParameterMention).resolveTypeAt(path)
292292
}
293293

294+
/**
295+
* Holds if `me` is a call to the `panic!` macro.
296+
*
297+
* `panic!` needs special treatment, because it expands to a block expression
298+
* that looks like it should have type `()` instead of the correct `!` type.
299+
*/
300+
pragma[nomagic]
301+
private predicate isPanicMacroCall(MacroExpr me) {
302+
me.getMacroCall().resolveMacro().(MacroRules).getName().getText() = "panic"
303+
}
304+
294305
/** Module for inferring certain type information. */
295306
module CertainTypeInference {
296307
pragma[nomagic]
@@ -443,6 +454,14 @@ module CertainTypeInference {
443454
or
444455
result = inferCastExprType(n, path)
445456
or
457+
exprHasUnitType(n) and
458+
path.isEmpty() and
459+
result instanceof UnitType
460+
or
461+
isPanicMacroCall(n) and
462+
path.isEmpty() and
463+
result instanceof NeverType
464+
or
446465
infersCertainTypeAt(n, path, result.getATypeParameter())
447466
}
448467

@@ -579,7 +598,8 @@ private predicate typeEquality(AstNode n1, TypePath prefix1, AstNode n2, TypePat
579598
n2 = be.getRhs()
580599
)
581600
or
582-
n1 = n2.(MacroExpr).getMacroCall().getMacroCallExpansion()
601+
n1 = n2.(MacroExpr).getMacroCall().getMacroCallExpansion() and
602+
not isPanicMacroCall(n2)
583603
or
584604
n1 = n2.(MacroPat).getMacroCall().getMacroCallExpansion()
585605
or
@@ -931,14 +951,17 @@ private predicate functionInfoBlanketLike(
931951
*/
932952
bindingset[path, type]
933953
private predicate isComplexRootStripped(TypePath path, Type type) {
934-
path.isEmpty() and
935-
not validSelfType(type)
936-
or
937-
exists(TypeParameter tp |
938-
complexSelfRoot(_, tp) and
939-
path = TypePath::singleton(tp) and
940-
exists(type)
941-
)
954+
(
955+
path.isEmpty() and
956+
not validSelfType(type)
957+
or
958+
exists(TypeParameter tp |
959+
complexSelfRoot(_, tp) and
960+
path = TypePath::singleton(tp) and
961+
exists(type)
962+
)
963+
) and
964+
type != TNeverType()
942965
}
943966

944967
/**
@@ -1540,7 +1563,8 @@ private module MethodResolution {
15401563
MethodCall getMethodCall() { result = mc_ }
15411564

15421565
Type getTypeAt(TypePath path) {
1543-
result = mc_.getACandidateReceiverTypeAtSubstituteLookupTraits(derefChain, borrow, path)
1566+
result = mc_.getACandidateReceiverTypeAtSubstituteLookupTraits(derefChain, borrow, path) and
1567+
not result = TNeverType()
15441568
}
15451569

15461570
pragma[nomagic]
@@ -2810,7 +2834,8 @@ private predicate isReturnExprCfgAncestor(AstNode n) {
28102834
pragma[nomagic]
28112835
predicate isUnitBlockExpr(BlockExpr be) {
28122836
not be.getStmtList().hasTailExpr() and
2813-
not isReturnExprCfgAncestor(be)
2837+
not isReturnExprCfgAncestor(be) and
2838+
not be.hasLabel()
28142839
}
28152840

28162841
pragma[nomagic]
@@ -2831,6 +2856,15 @@ private Type inferBlockExprType(BlockExpr be, TypePath path) {
28312856
)
28322857
}
28332858

2859+
pragma[nomagic]
2860+
private predicate exprHasUnitType(Expr e) {
2861+
e = any(IfExpr ie | not ie.hasElse())
2862+
or
2863+
e instanceof WhileExpr
2864+
or
2865+
e instanceof ForExpr
2866+
}
2867+
28342868
final private class AwaitTarget extends Expr {
28352869
AwaitTarget() { this = any(AwaitExpr ae).getExpr() }
28362870

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,11 @@ TypeMention getSelfParamTypeMention(SelfParam self) {
444444
}
445445

446446
/**
447-
* An element used to represent the implicit `()` return type of function.
447+
* An element used to represent the implicit `()` return type of a function.
448+
*
449+
* Since the implicit type does not appear in the AST, we (somewhat arbitrarily)
450+
* choose the name of the function as a type mention. This works because there
451+
* is a one-to-one correspondence between a function and its name.
448452
*/
449453
class ShorthandReturnTypeMention extends TypeMention instanceof Name {
450454
private Function f;

rust/ql/lib/codeql/rust/internal/typeinference/BlanketImplementation.qll

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,10 @@ module SatisfiesBlanketConstraint<
9090

9191
Location getLocation() { result = at.getLocation() }
9292

93-
Type getTypeAt(TypePath path) { result = at.getTypeAt(blanketPath.appendInverse(path)) }
93+
Type getTypeAt(TypePath path) {
94+
result = at.getTypeAt(blanketPath.appendInverse(path)) and
95+
not result = TNeverType()
96+
}
9497

9598
string toString() { result = at.toString() + " [blanket at " + blanketPath.toString() + "]" }
9699
}

rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class FunctionPosition extends TFunctionPosition {
4646
result = f.getParam(this.asPosition()).getTypeRepr()
4747
or
4848
this.isReturn() and
49-
result = f.getRetType().getTypeRepr()
49+
result = getReturnTypeMention(f)
5050
}
5151

5252
string toString() {
@@ -263,7 +263,10 @@ module ArgIsInstantiationOf<
263263
final private class ArgFinal = Arg;
264264

265265
private class ArgSubst extends ArgFinal {
266-
Type getTypeAt(TypePath path) { result = substituteLookupTraits(super.getTypeAt(path)) }
266+
Type getTypeAt(TypePath path) {
267+
result = substituteLookupTraits(super.getTypeAt(path)) and
268+
not result = TNeverType()
269+
}
267270
}
268271

269272
private module IsInstantiationOfInput implements
@@ -368,10 +371,10 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
368371
CallAndPos cp, Input::Call call, FunctionPosition pos, int rnk, Function f,
369372
TypeAbstraction abs, AssocFunctionType constraint
370373
) {
371-
cp = MkCallAndPos(call, pos) and
374+
cp = MkCallAndPos(call, pragma[only_bind_into](pos)) and
372375
call.hasTargetCand(abs, f) and
373-
toCheckRanked(abs, f, pos, rnk) and
374-
Input::toCheck(abs, f, pos, constraint)
376+
toCheckRanked(abs, f, pragma[only_bind_into](pos), rnk) and
377+
Input::toCheck(abs, f, pragma[only_bind_into](pos), constraint)
375378
}
376379

377380
pragma[nomagic]

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2841,7 +2841,7 @@ mod block_types {
28412841
#[rustfmt::skip]
28422842
fn f1(cond: bool) -> i32 {
28432843
// Block that evaluates to unit
2844-
let a = { // $ MISSING: type=a:()
2844+
let a = { // $ type=a:()
28452845
if cond {
28462846
return 12;
28472847
}
@@ -2852,7 +2852,7 @@ mod block_types {
28522852
#[rustfmt::skip]
28532853
fn f2() -> i32 {
28542854
// Block that does not evaluate to unit
2855-
let b = 'label: { // $ MISSING: b:i32 SPURIOUS: certainType=b:()
2855+
let b = 'label: { // $ MISSING: b:i32
28562856
break 'label 12;
28572857
};
28582858
println!("b: {:?}", b);

0 commit comments

Comments
 (0)