Skip to content

Commit 95e60ad

Browse files
authored
Merge pull request #20705 from hvitved/rust/type-inference-unit
Rust: Infer more `()` types
2 parents d8fff44 + 7d5664f commit 95e60ad

File tree

22 files changed

+2577
-1421
lines changed

22 files changed

+2577
-1421
lines changed

rust/ql/.generated.list

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/lib/codeql/rust/elements/RetTypeRepr.qll

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/lib/codeql/rust/elements/UseBoundGenericArgs.qll

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/lib/codeql/rust/elements/internal/RetTypeReprImpl.qll

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/lib/codeql/rust/elements/internal/UseBoundGenericArgsImpl.qll

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/lib/codeql/rust/elements/internal/generated/Raw.qll

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/lib/codeql/rust/elements/internal/generated/RetTypeRepr.qll

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/lib/codeql/rust/elements/internal/generated/UseBoundGenericArgs.qll

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 74 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,14 @@ import M2
232232
module Consistency {
233233
import M2::Consistency
234234

235+
private Type inferCertainTypeAdj(AstNode n, TypePath path) {
236+
result = CertainTypeInference::inferCertainType(n, path) and
237+
not result = TNeverType()
238+
}
239+
235240
predicate nonUniqueCertainType(AstNode n, TypePath path, Type t) {
236-
strictcount(CertainTypeInference::inferCertainType(n, path)) > 1 and
237-
t = CertainTypeInference::inferCertainType(n, path) and
241+
strictcount(inferCertainTypeAdj(n, path)) > 1 and
242+
t = inferCertainTypeAdj(n, path) and
238243
// Suppress the inconsistency if `n` is a self parameter and the type
239244
// mention for the self type has multiple types for a path.
240245
not exists(ImplItemNode impl, TypePath selfTypePath |
@@ -278,7 +283,7 @@ private TypeMention getTypeAnnotation(AstNode n) {
278283
)
279284
or
280285
exists(Function f |
281-
result = f.getRetType().getTypeRepr() and
286+
result = getReturnTypeMention(f) and
282287
n = f.getFunctionBody()
283288
)
284289
}
@@ -291,6 +296,17 @@ private Type inferAnnotatedType(AstNode n, TypePath path) {
291296
result = n.(ShorthandSelfParameterMention).resolveTypeAt(path)
292297
}
293298

299+
/**
300+
* Holds if `me` is a call to the `panic!` macro.
301+
*
302+
* `panic!` needs special treatment, because it expands to a block expression
303+
* that looks like it should have type `()` instead of the correct `!` type.
304+
*/
305+
pragma[nomagic]
306+
private predicate isPanicMacroCall(MacroExpr me) {
307+
me.getMacroCall().resolveMacro().(MacroRules).getName().getText() = "panic"
308+
}
309+
294310
/** Module for inferring certain type information. */
295311
module CertainTypeInference {
296312
pragma[nomagic]
@@ -436,14 +452,21 @@ module CertainTypeInference {
436452
result = inferTupleRootType(n) and
437453
path.isEmpty()
438454
or
439-
result = inferAsyncBlockExprRootType(n) and
440-
path.isEmpty()
455+
result = inferBlockExprType(n, path)
441456
or
442457
result = inferArrayExprType(n) and
443458
path.isEmpty()
444459
or
445460
result = inferCastExprType(n, path)
446461
or
462+
exprHasUnitType(n) and
463+
path.isEmpty() and
464+
result instanceof UnitType
465+
or
466+
isPanicMacroCall(n) and
467+
path.isEmpty() and
468+
result instanceof NeverType
469+
or
447470
infersCertainTypeAt(n, path, result.getATypeParameter())
448471
}
449472

@@ -580,7 +603,8 @@ private predicate typeEquality(AstNode n1, TypePath prefix1, AstNode n2, TypePat
580603
n2 = be.getRhs()
581604
)
582605
or
583-
n1 = n2.(MacroExpr).getMacroCall().getMacroCallExpansion()
606+
n1 = n2.(MacroExpr).getMacroCall().getMacroCallExpansion() and
607+
not isPanicMacroCall(n2)
584608
or
585609
n1 = n2.(MacroPat).getMacroCall().getMacroCallExpansion()
586610
or
@@ -932,14 +956,17 @@ private predicate functionInfoBlanketLike(
932956
*/
933957
bindingset[path, type]
934958
private predicate isComplexRootStripped(TypePath path, Type type) {
935-
path.isEmpty() and
936-
not validSelfType(type)
937-
or
938-
exists(TypeParameter tp |
939-
complexSelfRoot(_, tp) and
940-
path = TypePath::singleton(tp) and
941-
exists(type)
942-
)
959+
(
960+
path.isEmpty() and
961+
not validSelfType(type)
962+
or
963+
exists(TypeParameter tp |
964+
complexSelfRoot(_, tp) and
965+
path = TypePath::singleton(tp) and
966+
exists(type)
967+
)
968+
) and
969+
type != TNeverType()
943970
}
944971

945972
/**
@@ -1541,7 +1568,8 @@ private module MethodResolution {
15411568
MethodCall getMethodCall() { result = mc_ }
15421569

15431570
Type getTypeAt(TypePath path) {
1544-
result = mc_.getACandidateReceiverTypeAtSubstituteLookupTraits(derefChain, borrow, path)
1571+
result = mc_.getACandidateReceiverTypeAtSubstituteLookupTraits(derefChain, borrow, path) and
1572+
not result = TNeverType()
15451573
}
15461574

15471575
pragma[nomagic]
@@ -1854,7 +1882,7 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi
18541882
}
18551883

18561884
private Type resolveRetType(TypePath path) {
1857-
result = this.getRetType().getTypeRepr().(TypeMention).resolveTypeAt(path)
1885+
result = getReturnTypeMention(this).resolveTypeAt(path)
18581886
}
18591887

18601888
pragma[nomagic]
@@ -2799,10 +2827,37 @@ private AssociatedTypeTypeParameter getFutureOutputTypeParameter() {
27992827
}
28002828

28012829
pragma[nomagic]
2802-
private TraitType inferAsyncBlockExprRootType(AsyncBlockExpr abe) {
2830+
predicate isUnitBlockExpr(BlockExpr be) {
2831+
not be.getStmtList().hasTailExpr() and
2832+
not be = any(Callable c).getBody() and
2833+
not be.hasLabel()
2834+
}
2835+
2836+
pragma[nomagic]
2837+
private Type inferBlockExprType(BlockExpr be, TypePath path) {
28032838
// `typeEquality` handles the non-root case
2804-
exists(abe) and
2805-
result = getFutureTraitType()
2839+
if be instanceof AsyncBlockExpr
2840+
then (
2841+
path.isEmpty() and
2842+
result = getFutureTraitType()
2843+
or
2844+
isUnitBlockExpr(be) and
2845+
path = TypePath::singleton(getFutureOutputTypeParameter()) and
2846+
result instanceof UnitType
2847+
) else (
2848+
isUnitBlockExpr(be) and
2849+
path.isEmpty() and
2850+
result instanceof UnitType
2851+
)
2852+
}
2853+
2854+
pragma[nomagic]
2855+
private predicate exprHasUnitType(Expr e) {
2856+
e = any(IfExpr ie | not ie.hasElse())
2857+
or
2858+
e instanceof WhileExpr
2859+
or
2860+
e instanceof ForExpr
28062861
}
28072862

28082863
final private class AwaitTarget extends Expr {

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,34 @@ TypeMention getSelfParamTypeMention(SelfParam self) {
443443
result = self.getTypeRepr()
444444
}
445445

446+
/**
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.
452+
*/
453+
class ShorthandReturnTypeMention extends TypeMention instanceof Name {
454+
private Function f;
455+
456+
ShorthandReturnTypeMention() {
457+
this = f.getName() and
458+
not f.getRetType().hasTypeRepr()
459+
}
460+
461+
override Type resolveTypeAt(TypePath typePath) {
462+
typePath.isEmpty() and
463+
result instanceof UnitType
464+
}
465+
}
466+
467+
pragma[nomagic]
468+
TypeMention getReturnTypeMention(Function f) {
469+
result.(ShorthandReturnTypeMention) = f.getName()
470+
or
471+
result = f.getRetType().getTypeRepr()
472+
}
473+
446474
class DynTraitTypeReprMention extends TypeMention instanceof DynTraitTypeRepr {
447475
private DynTraitType dynType;
448476

0 commit comments

Comments
 (0)