Skip to content

Commit 4ef4593

Browse files
committed
Type inference: Improve base type matching
1 parent f8dff20 commit 4ef4593

3 files changed

Lines changed: 93 additions & 3 deletions

File tree

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

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1504,6 +1504,80 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
15041504
hasNotTypeArgument(a, target, tp)
15051505
)
15061506
}
1507+
1508+
predicate baseTypeMatchAtTypeParameter(
1509+
Access a, AccessEnvironment e, AccessPosition apos, Declaration target, TypeParameter tp,
1510+
TypePath prefix, TypePath requiredPrefix
1511+
) {
1512+
exists(
1513+
TypePath pathToTypeParamInConstraint, TypePath pathToTp, TypePath pathToTypeParamInSub
1514+
|
1515+
argRootTypeSatisfiesTargetTypeCand(_, target, pragma[only_bind_into](apos), tp, pathToTp) and
1516+
SatisfiesParameterConstraint::satisfiesConstraintAtTypeParameter(MkRelevantAccess(a,
1517+
pragma[only_bind_into](apos), e),
1518+
MkRelevantTarget(target, pragma[only_bind_into](apos)), pathToTypeParamInConstraint,
1519+
pathToTypeParamInSub) and
1520+
hasNotTypeArgument(a, target, tp)
1521+
|
1522+
/*
1523+
* Example:
1524+
*
1525+
* ```swift
1526+
* class Base<B> {
1527+
* init(_ value: B) {}
1528+
* }
1529+
*
1530+
* class Derived<D>: Base<[D]> {
1531+
* init(_ value: D) { super.init([value]) }
1532+
* }
1533+
*
1534+
* func foo<T>(_ value: T, _ base: Base<T>) { }
1535+
*
1536+
* foo([2], Derived(<unknown>))
1537+
* ```
1538+
*
1539+
* - tp = T (bound by `foo`)
1540+
* - prefix = pathToTypeParamInSub = "D"
1541+
* - requiredPrefix = "Element"
1542+
* - pathToTypeParamInConstraint = "B.Element"
1543+
* - pathToTp = "B"
1544+
*/
1545+
1546+
pathToTypeParamInConstraint = pathToTp.appendInverse(requiredPrefix) and
1547+
prefix = pathToTypeParamInSub
1548+
or
1549+
/*
1550+
* Example:
1551+
*
1552+
* ```swift
1553+
* class Base<B> {
1554+
* init(_ value: B) {}
1555+
* }
1556+
*
1557+
* class Derived<D>: Base<D> {
1558+
* override init(_ value: D) { super.init(value) }
1559+
* }
1560+
*
1561+
* func foo<T>(_ value: T, _ base: Base<T?>) {}
1562+
*
1563+
* foo(2, Derived2(Optional.none))
1564+
* ```
1565+
*
1566+
* - tp = T (bound by `foo`)
1567+
* - prefix = "D.Wrapped"
1568+
* - pathToTypeParamInSub = "D"
1569+
* - requiredPrefix = ""
1570+
* - pathToTypeParamInConstraint = "B"
1571+
* - pathToTp = "B.Wrapped"
1572+
*/
1573+
1574+
exists(TypePath path0 |
1575+
pathToTp = pathToTypeParamInConstraint.appendInverse(path0) and
1576+
prefix = pathToTypeParamInSub.append(path0) and
1577+
requiredPrefix = TypePath::nil()
1578+
)
1579+
)
1580+
}
15071581
}
15081582

15091583
private module AccessConstraint {
@@ -1745,6 +1819,16 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
17451819
)
17461820
)
17471821
or
1822+
exists(
1823+
Declaration target, TypePath prefix, TypePath requiredPrefix, TypePath suffix,
1824+
TypeParameter tp
1825+
|
1826+
AccessBaseType::baseTypeMatchAtTypeParameter(a, e, apos, target, tp, prefix,
1827+
requiredPrefix) and
1828+
typeMatch(a, e, target, requiredPrefix.appendInverse(suffix), result, tp) and
1829+
path = prefix.append(suffix)
1830+
)
1831+
or
17481832
exists(
17491833
Declaration target, TypePath prefix, TypeMention constraint,
17501834
TypePath pathToTypeParamInConstraint, TypePath pathToTypeParamInSub

‎unified/ql/test/library-tests/type-inference/generics.swift‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,15 +208,15 @@ func testDerived() {
208208

209209
let x = foo(false, [2], DerivedDerived(unknown())) // $ target=foo target=DerivedDerived.init target=unknown type=x@DerivedDerived<D>:Int
210210

211-
foo2(false, [2], DerivedDerived(unknown())) // $ target=foo2 target=DerivedDerived.init target=unknown $ MISSING: type=DerivedDerived(...)@DerivedDerived<D>:Int
211+
foo2(false, [2], DerivedDerived(unknown())) // $ target=foo2 target=DerivedDerived.init target=unknown type=DerivedDerived(...)@DerivedDerived<D>:Int
212212

213213
let y = bar(false, 2, DerivedDerived(unknown())) // $ type=y@DerivedDerived<D>:Int target=bar target=DerivedDerived.init target=unknown
214214

215-
bar2(false, 2, DerivedDerived(unknown())) // $ target=bar2 target=DerivedDerived.init target=unknown $ MISSING: type=DerivedDerived(...)@DerivedDerived<D>:Int
215+
bar2(false, 2, DerivedDerived(unknown())) // $ target=bar2 target=DerivedDerived.init target=unknown type=DerivedDerived(...)@DerivedDerived<D>:Int
216216

217217
let w = baz(false, 2, Derived(Optional.none)) // $ type=w@Derived<T1>.Optional<Wrapped>:Int target=baz target=Derived.init field=Optional.none
218218

219-
baz2(false, 2, Derived(Optional.none)) // $ target=baz2 target=Derived.init field=Optional.none $ MISSING: type=Derived(...)@Derived<T1>.Optional<Wrapped>:Int
219+
baz2(false, 2, Derived(Optional.none)) // $ target=baz2 target=Derived.init field=Optional.none type=Derived(...)@Derived<T1>.Optional<Wrapped>:Int
220220
}
221221

222222
// --- Generics and protocols ---

‎unified/ql/test/library-tests/type-inference/type-inference.expected‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1425,6 +1425,8 @@ inferType
14251425
| generics.swift:211:15:211:17 | ArrayLiteral | Element | {EXTERNAL LOCATION} | Int |
14261426
| generics.swift:211:16:211:16 | 2 | | {EXTERNAL LOCATION} | Int |
14271427
| generics.swift:211:20:211:44 | DerivedDerived(...) | | generics.swift:164:1:172:1 | DerivedDerived |
1428+
| generics.swift:211:20:211:44 | DerivedDerived(...) | D | {EXTERNAL LOCATION} | Int |
1429+
| generics.swift:211:35:211:43 | unknown(...) | | {EXTERNAL LOCATION} | Int |
14281430
| generics.swift:213:7:213:7 | y | | generics.swift:164:1:172:1 | DerivedDerived |
14291431
| generics.swift:213:7:213:7 | y | D | {EXTERNAL LOCATION} | Int |
14301432
| generics.swift:213:11:213:50 | bar(...) | | generics.swift:164:1:172:1 | DerivedDerived |
@@ -1437,6 +1439,8 @@ inferType
14371439
| generics.swift:215:8:215:12 | false | | {EXTERNAL LOCATION} | Bool |
14381440
| generics.swift:215:15:215:15 | 2 | | {EXTERNAL LOCATION} | Int |
14391441
| generics.swift:215:18:215:42 | DerivedDerived(...) | | generics.swift:164:1:172:1 | DerivedDerived |
1442+
| generics.swift:215:18:215:42 | DerivedDerived(...) | D | {EXTERNAL LOCATION} | Int |
1443+
| generics.swift:215:33:215:41 | unknown(...) | | {EXTERNAL LOCATION} | Int |
14401444
| generics.swift:217:7:217:7 | w | | generics.swift:154:1:162:1 | Derived |
14411445
| generics.swift:217:7:217:7 | w | T1 | {EXTERNAL LOCATION} | Optional |
14421446
| generics.swift:217:7:217:7 | w | T1.Wrapped | {EXTERNAL LOCATION} | Int |
@@ -1456,7 +1460,9 @@ inferType
14561460
| generics.swift:219:15:219:15 | 2 | | {EXTERNAL LOCATION} | Int |
14571461
| generics.swift:219:18:219:39 | Derived(...) | | generics.swift:154:1:162:1 | Derived |
14581462
| generics.swift:219:18:219:39 | Derived(...) | T1 | {EXTERNAL LOCATION} | Optional |
1463+
| generics.swift:219:18:219:39 | Derived(...) | T1.Wrapped | {EXTERNAL LOCATION} | Int |
14591464
| generics.swift:219:26:219:38 | ... .none | | {EXTERNAL LOCATION} | Optional |
1465+
| generics.swift:219:26:219:38 | ... .none | Wrapped | {EXTERNAL LOCATION} | Int |
14601466
| generics.swift:231:22:233:3 | Block | | generics.swift:224:1:228:1 | MyProtocol2 |
14611467
| generics.swift:232:12:232:15 | self | | generics.swift:224:1:228:1 | MyProtocol2 |
14621468
| generics.swift:237:7:237:11 | value | | generics.swift:236:15:236:15 | T |

0 commit comments

Comments
 (0)