Skip to content

Commit 468caa3

Browse files
committed
Type inference: Improve base type matching
1 parent 70e4424 commit 468caa3

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, Derived(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
@@ -204,15 +204,15 @@ func testDerived() {
204204

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

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

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

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

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

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

218218
// --- 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
@@ -1429,7 +1429,9 @@ inferType
14291429
| generics.swift:207:15:207:17 | ArrayLiteral | Element | {EXTERNAL LOCATION} | Int |
14301430
| generics.swift:207:16:207:16 | 2 | | {EXTERNAL LOCATION} | Int |
14311431
| generics.swift:207:20:207:37 | DerivedDerived(...) | | generics.swift:164:1:172:1 | DerivedDerived |
1432+
| generics.swift:207:20:207:37 | DerivedDerived(...) | D | {EXTERNAL LOCATION} | Int |
14321433
| generics.swift:207:35:207:36 | ArrayLiteral | | {EXTERNAL LOCATION} | Array |
1434+
| generics.swift:207:35:207:36 | ArrayLiteral | Element | {EXTERNAL LOCATION} | Int |
14331435
| generics.swift:209:7:209:7 | y | | generics.swift:164:1:172:1 | DerivedDerived |
14341436
| generics.swift:209:7:209:7 | y | D | {EXTERNAL LOCATION} | Int |
14351437
| generics.swift:209:11:209:43 | bar(...) | | generics.swift:164:1:172:1 | DerivedDerived |
@@ -1443,7 +1445,9 @@ inferType
14431445
| generics.swift:211:8:211:12 | false | | {EXTERNAL LOCATION} | Bool |
14441446
| generics.swift:211:15:211:15 | 2 | | {EXTERNAL LOCATION} | Int |
14451447
| generics.swift:211:18:211:35 | DerivedDerived(...) | | generics.swift:164:1:172:1 | DerivedDerived |
1448+
| generics.swift:211:18:211:35 | DerivedDerived(...) | D | {EXTERNAL LOCATION} | Int |
14461449
| generics.swift:211:33:211:34 | ArrayLiteral | | {EXTERNAL LOCATION} | Array |
1450+
| generics.swift:211:33:211:34 | ArrayLiteral | Element | {EXTERNAL LOCATION} | Int |
14471451
| generics.swift:213:7:213:7 | w | | generics.swift:154:1:162:1 | Derived |
14481452
| generics.swift:213:7:213:7 | w | T1 | {EXTERNAL LOCATION} | Optional |
14491453
| generics.swift:213:7:213:7 | w | T1.Wrapped | {EXTERNAL LOCATION} | Int |
@@ -1463,7 +1467,9 @@ inferType
14631467
| generics.swift:215:15:215:15 | 2 | | {EXTERNAL LOCATION} | Int |
14641468
| generics.swift:215:18:215:39 | Derived(...) | | generics.swift:154:1:162:1 | Derived |
14651469
| generics.swift:215:18:215:39 | Derived(...) | T1 | {EXTERNAL LOCATION} | Optional |
1470+
| generics.swift:215:18:215:39 | Derived(...) | T1.Wrapped | {EXTERNAL LOCATION} | Int |
14661471
| generics.swift:215:26:215:38 | ... .none | | {EXTERNAL LOCATION} | Optional |
1472+
| generics.swift:215:26:215:38 | ... .none | Wrapped | {EXTERNAL LOCATION} | Int |
14671473
| generics.swift:227:22:229:3 | Block | | generics.swift:220:1:224:1 | MyProtocol2 |
14681474
| generics.swift:228:12:228:15 | self | | generics.swift:220:1:224:1 | MyProtocol2 |
14691475
| generics.swift:233:7:233:11 | value | | generics.swift:232:15:232:15 | T |

0 commit comments

Comments
 (0)