Skip to content

Commit 309756c

Browse files
committed
Rust: Model String -> str implicit conversion in type inference
1 parent d3eed0d commit 309756c

File tree

3 files changed

+28
-6
lines changed

3 files changed

+28
-6
lines changed

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

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,12 +1153,27 @@ private module MethodCall {
11531153

11541154
pragma[nomagic]
11551155
override Type getTypeAt(TypePath path) {
1156-
exists(TypePath path0 | result = inferType(super.getReceiver(), path0) |
1157-
path0.isCons(TRefTypeParameter(), path)
1156+
exists(TypePath path0, Type t0 |
1157+
t0 = inferType(super.getReceiver(), path0) and
1158+
(
1159+
path0.isCons(TRefTypeParameter(), path)
1160+
or
1161+
not path0.isCons(TRefTypeParameter(), _) and
1162+
not (path0.isEmpty() and result = TRefType()) and
1163+
path = path0
1164+
)
1165+
|
1166+
result = t0
11581167
or
1159-
not path0.isCons(TRefTypeParameter(), _) and
1160-
not (path0.isEmpty() and result = TRefType()) and
1161-
path = path0
1168+
// We do not yet model the `Deref` trait, so we hard-code the fact that
1169+
// `String` dereferences to `str` here. This allows us e.g. to resolve
1170+
// `x.parse::<usize>()` to the function `<core::str>::parse` when `x` has
1171+
// type `String`.
1172+
//
1173+
// See also https://doc.rust-lang.org/reference/expressions/method-call-expr.html#r-expr.method.autoref-deref
1174+
path.isEmpty() and
1175+
t0.(StructType).asItemNode().(Struct).getCanonicalPath() = "alloc::string::String" and
1176+
result.(StructType).asItemNode() instanceof Builtins::Str
11621177
)
11631178
}
11641179
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1111,7 +1111,7 @@ mod method_call_type_conversion {
11111111
let x9 : String = "Hello".to_string(); // $ type=x9:String
11121112
// Implicit `String` -> `str` conversion happense via the `Deref` trait:
11131113
// https://doc.rust-lang.org/std/string/struct.String.html#deref.
1114-
let u = x9.parse::<u32>(); // $ MISSING: method=parse type=u:T.u32
1114+
let u = x9.parse::<u32>(); // $ method=parse type=u:T.u32
11151115
}
11161116
}
11171117

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,9 +1390,16 @@ inferType
13901390
| main.rs:1109:26:1109:27 | x7 | T | file://:0:0:0:0 | & |
13911391
| main.rs:1109:26:1109:27 | x7 | T.&T | main.rs:1060:5:1061:14 | S2 |
13921392
| main.rs:1111:13:1111:14 | x9 | | {EXTERNAL LOCATION} | String |
1393+
| main.rs:1111:13:1111:14 | x9 | | {EXTERNAL LOCATION} | str |
13931394
| main.rs:1111:27:1111:33 | "Hello" | | {EXTERNAL LOCATION} | str |
13941395
| main.rs:1111:27:1111:45 | "Hello".to_string() | | {EXTERNAL LOCATION} | String |
1396+
| main.rs:1111:27:1111:45 | "Hello".to_string() | | {EXTERNAL LOCATION} | str |
1397+
| main.rs:1114:13:1114:13 | u | | {EXTERNAL LOCATION} | Result |
1398+
| main.rs:1114:13:1114:13 | u | T | {EXTERNAL LOCATION} | u32 |
13951399
| main.rs:1114:17:1114:18 | x9 | | {EXTERNAL LOCATION} | String |
1400+
| main.rs:1114:17:1114:18 | x9 | | {EXTERNAL LOCATION} | str |
1401+
| main.rs:1114:17:1114:33 | x9.parse() | | {EXTERNAL LOCATION} | Result |
1402+
| main.rs:1114:17:1114:33 | x9.parse() | T | {EXTERNAL LOCATION} | u32 |
13961403
| main.rs:1121:16:1121:20 | SelfParam | | file://:0:0:0:0 | & |
13971404
| main.rs:1121:16:1121:20 | SelfParam | &T | main.rs:1119:5:1127:5 | Self [trait MyTrait] |
13981405
| main.rs:1124:16:1124:20 | SelfParam | | file://:0:0:0:0 | & |

0 commit comments

Comments
 (0)