Skip to content

Commit ea01633

Browse files
committed
wip3
1 parent ddae01c commit ea01633

4 files changed

Lines changed: 147 additions & 80 deletions

File tree

‎unified/ql/lib/codeql/unified/internal/typeinference/TypeInferenceConsistency.qll‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ query predicate nonUniqueCertainType(AstNode n, TypePath path) {
2121

2222
query predicate typeParameterEscape(AstNode n, TypePath path, TypeParameter tp) {
2323
tp = inferType(n, path) and
24-
forex(AstNode scope | tp.getScope() = scope | not n.getParent*() = scope)
24+
not n.getParent*() = tp.getScope()
2525
}

‎unified/ql/lib/codeql/unified/internal/typeinference/TypeMention.qll‎

Lines changed: 85 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,6 @@ private import TypeInferencePlugin as Plugin
55
private import codeql.unified.internal.StaticNameBinding
66
private import codeql.unified.internal.ExprPositions
77

8-
// private predicate isTypeParameterAlias(TypeAliasDeclaration alias, int i) {
9-
// exists(Unified::TypeParameter tp |
10-
// tp = alias.getTypeParameter(i) and
11-
// tp.getNameNode() = getTypeFromRef(alias.getType())
12-
// )
13-
// }
148
final class TypeMention = TypeMentionImpl;
159

1610
/** An AST node that mentions a type. */
@@ -33,10 +27,78 @@ abstract private class TypeMentionImpl extends AstNode {
3327
}
3428

3529
/**
36-
* Gets the type mentioned at `path`.
30+
* Gets the type mentioned explicitly at `path`.
31+
*
32+
* This predicate is an internal implementation detail; use `getTypeAt` instead.
3733
*/
3834
pragma[nomagic]
39-
abstract Type getTypeAt(TypePath path);
35+
abstract Type getExplicitTypeAt(TypePath path);
36+
37+
pragma[nomagic]
38+
private ClassLikeDeclaration getImplicitEnclosingCand(TypePath path, ParentTypeParameterType tp) {
39+
exists(ClassLikeDeclaration nested |
40+
nested = this.getExplicitTypeAt(path).(ClassLikeDeclarationType).getClassLikeDeclaration() and
41+
tp = TParentTypeParameterType(nested) and
42+
not exists(this.getExplicitTypeAt(path.append(TypePath::singleton(tp)))) and
43+
result = this.getEnclosingClassResolved+()
44+
)
45+
}
46+
47+
/**
48+
* Gets the type mentioned at `path`.
49+
*/
50+
Type getTypeAt(TypePath path) {
51+
result = this.getExplicitTypeAt(path)
52+
or
53+
// A mention of a nested type without an explicit qualifier implicitly mentions
54+
// the parent type (including at the identifer that introduces the type)
55+
//
56+
// ```swift
57+
// class Outer {
58+
// class Inner {
59+
// let y: Inner // short-hand for `Outer.Inner`
60+
// }
61+
// }
62+
// ```
63+
exists(
64+
TypePath prefix, ClassLikeDeclaration parent, ParentTypeParameterType tp, TypePath suffix,
65+
ClassLikeDeclaration encl
66+
|
67+
encl = this.getImplicitEnclosingCand(prefix, tp) and
68+
parent = tp.getParent() and
69+
path = prefix.append(TypePath::cons(tp, suffix)) and
70+
result = encl.getNameNode().(TypeMention).getTypeAt(suffix)
71+
|
72+
encl = parent
73+
or
74+
not parent = this.getImplicitEnclosingCand(_, _) and
75+
encl.getABaseClass+() = parent
76+
)
77+
or
78+
// A mention of a generic type without explicit type arguments and within
79+
// the scope of the type, implicitly mentions all type parameters (including
80+
// at the identifer that introduces the type):
81+
//
82+
// ```swift
83+
// class Generic<T> {
84+
// let x: Generic // short-hand for `Generic<T>
85+
// }
86+
// ```
87+
exists(TypePath prefix, ClassLikeDeclarationType t |
88+
t = this.getTypeAt(prefix) and
89+
forex(TypeParameter tp |
90+
tp = t.getATypeParameter() and not tp instanceof ParentTypeParameterType
91+
|
92+
not exists(this.getExplicitTypeAt(prefix.append(TypePath::singleton(tp))))
93+
) and
94+
t.getClassLikeDeclaration() = this.getEnclosingClassResolved+() and
95+
result = t.getATypeParameter() and
96+
path = prefix.append(TypePath::singleton(result)) and
97+
not result instanceof ParentTypeParameterType
98+
|
99+
isInTypeContextWithImplicitTypeArgs(this) or this = t.getNameNode()
100+
)
101+
}
40102

41103
/**
42104
* Gets an explicit qualifier that may refer to the parent type of this nested
@@ -139,7 +201,10 @@ abstract private class ExprTypeMentionImpl extends TypeMentionImpl, Expr {
139201
pragma[nomagic]
140202
private ClassLikeDeclaration getQualifierTypeAt(TypePath path) {
141203
result =
142-
this.getParentQualifier().getTypeAt(path).(ClassLikeDeclarationType).getClassLikeDeclaration() and
204+
this.getParentQualifier()
205+
.getExplicitTypeAt(path)
206+
.(ClassLikeDeclarationType)
207+
.getClassLikeDeclaration() and
143208
forall(TypeParameter tp | tp = path.getElement(_) | tp instanceof ParentTypeParameterType)
144209
}
145210

@@ -149,7 +214,7 @@ abstract private class ExprTypeMentionImpl extends TypeMentionImpl, Expr {
149214
parent = tp.getParent()
150215
}
151216

152-
final override Type getTypeAt(TypePath path) {
217+
final override Type getExplicitTypeAt(TypePath path) {
153218
// recursion guard to check that `getType` does not recursively depend on `getTypeAt`
154219
(exists(this.getType()) implies any()) and
155220
result = this.getTypeAtImpl(path)
@@ -159,45 +224,8 @@ abstract private class ExprTypeMentionImpl extends TypeMentionImpl, Expr {
159224
qualifier = this.getParentQualifier() and
160225
this.isNestedClass(tp, this.getQualifierTypeAt(prefix)) and
161226
path = TypePath::cons(tp, suffix) and
162-
result = qualifier.getTypeAt(prefix.appendInverse(suffix))
227+
result = qualifier.getExplicitTypeAt(prefix.appendInverse(suffix))
163228
)
164-
or
165-
// A mention of a nested type without an explicit qualifier implicitly mentions
166-
// the parent type (including at the identifer that introduces the type)
167-
//
168-
// ```swift
169-
// class Outer {
170-
// class Inner {
171-
// let y: Inner // short-hand for `Outer.Inner`
172-
// }
173-
// }
174-
// ```
175-
exists(
176-
ClassLikeDeclaration encl, ClassLikeDeclaration parent, ParentTypeParameterType tp,
177-
TypePath suffix
178-
|
179-
encl = this.getImplicitEnclosingCand(tp) and
180-
parent = tp.getParent() and
181-
path = TypePath::cons(tp, suffix) and
182-
result = encl.getNameNode().(TypeMention).getTypeAt(suffix)
183-
|
184-
encl = parent
185-
or
186-
not parent = this.getImplicitEnclosingCand(tp) and
187-
encl.getABaseClass+() = parent
188-
)
189-
}
190-
191-
pragma[nomagic]
192-
private ClassLikeDeclaration getImplicitEnclosingCand(ParentTypeParameterType tp) {
193-
not this.hasParentQualifier() and
194-
not exists(TypeAliasDeclaration alias |
195-
this.getParent*() = alias.getType() //and
196-
// not this.getParent*() = any(GenericTypeExpr g).getATypeArgument() and
197-
// not this.getParent*() = any(TupleExpr t).getAnElement()
198-
) and
199-
tp = TParentTypeParameterType(this.getClassLikeDeclaration()) and
200-
result = this.getEnclosingClassResolved+()
201229
}
202230
}
203231

@@ -216,7 +244,7 @@ class AliasExprTypeMention extends ExprTypeMentionImpl {
216244
override TypePath getTypeArgumentPath(int i) {
217245
exists(TypeParameterType tp |
218246
tp = this.getAliasTypeParameter(i) and
219-
tp = alias.getType().(TypeMention).getTypeAt(result)
247+
tp = alias.getType().(TypeMention).getExplicitTypeAt(result)
220248
or
221249
// `typealias Alias = Generic`, where `Generic` has positional type parameters
222250
not exists(this.getAliasTypeParameter(_)) and
@@ -247,7 +275,7 @@ class AliasExprTypeMention extends ExprTypeMentionImpl {
247275
override Type getType() { result = alias.getType().(TypeMention).getType() }
248276

249277
override Type getTypeAtImpl(TypePath path) {
250-
result = alias.getType().(TypeMention).getTypeAt(path) and
278+
result = alias.getType().(TypeMention).getExplicitTypeAt(path) and
251279
not result = this.getAliasTypeParameter(_)
252280
}
253281
}
@@ -312,7 +340,7 @@ private class NonAliasExprTypeMention extends ExprTypeMentionImpl {
312340
alias = c.getAMember() and
313341
alias.getName() = name and
314342
path = TypePath::cons(baseTp, suffix) and
315-
result = alias.getType().(TypeMention).getTypeAt(suffix)
343+
result = alias.getType().(TypeMention).getExplicitTypeAt(suffix)
316344
)
317345
)
318346
or
@@ -323,40 +351,21 @@ private class NonAliasExprTypeMention extends ExprTypeMentionImpl {
323351
|
324352
exists(int i |
325353
prefix = Plugin::getFunctionExprParameterTypePath(t, fe.getNumberOfParameters(), i) and
326-
result = fe.getParameter(i).getType().(TypeMention).getTypeAt(suffix)
354+
result = fe.getParameter(i).getType().(TypeMention).getExplicitTypeAt(suffix)
327355
)
328356
or
329357
prefix = Plugin::getFunctionExprReturnTypePath(t) and
330-
result = fe.getReturnType().(TypeMention).getTypeAt(suffix)
358+
result = fe.getReturnType().(TypeMention).getExplicitTypeAt(suffix)
331359
)
332360
or
333361
this =
334362
any(TupleExpr te |
335363
exists(Plugin::TupleType tt, int i, TypePath suffix |
336364
tt.getArity() = te.getNumberOfElements() and
337-
result = te.getElement(i).getValue().(TypeMention).getTypeAt(suffix) and
365+
result = te.getElement(i).getValue().(TypeMention).getExplicitTypeAt(suffix) and
338366
path = TypePath::cons(tt.getPositionalTypeParameter(i), suffix)
339367
)
340368
)
341-
or
342-
// A mention of a generic type without explicit type arguments and within
343-
// the scope of the type, implicitly mentions all type parameters (including
344-
// at the identifer that introduces the type):
345-
//
346-
// ```swift
347-
// class Generic<T> {
348-
// let x: Generic // short-hand for `Generic<T>
349-
// }
350-
// ```
351-
not this = any(GenericTypeExpr g).getBase() and
352-
exists(ClassLikeDeclarationType rootType |
353-
rootType = this.getType() and
354-
(isInTypeContextWithImplicitTypeArgs(this) or this = rootType.getNameNode()) and
355-
rootType.getClassLikeDeclaration() = this.getEnclosingClassResolved+() and
356-
result = rootType.getATypeParameter() and
357-
path = TypePath::singleton(result) and
358-
not result instanceof ParentTypeParameterType
359-
)
360369
}
361370

362371
override TypeMention resolve() { result = this }
@@ -379,11 +388,11 @@ private class GenericTypeExprTypeMention extends TypeMentionImpl, GenericTypeExp
379388

380389
pragma[nomagic]
381390
private Type getTypeArgumentAt(int i, TypePath path) {
382-
result = this.getTypeArgument(i).(TypeMention).getTypeAt(path)
391+
result = this.getTypeArgument(i).(TypeMention).getExplicitTypeAt(path)
383392
}
384393

385-
override Type getTypeAt(TypePath path) {
386-
result = base.getTypeAt(path)
394+
override Type getExplicitTypeAt(TypePath path) {
395+
result = base.getExplicitTypeAt(path)
387396
or
388397
base = this.getBase() and
389398
exists(int i, TypePath prefix, TypePath suffix |

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,17 +107,17 @@ class Outer<TOuter> {
107107
typealias Pair = (Inner<Int>, Inner<Int>)
108108

109109
func f3(p: Pair) {
110-
let outer = p.0.getOuter() // $ target=Outer.Inner.getOuter field=Tuple2.0 $ MISSING: type=outer:TOuter
110+
let outer = p.0.getOuter() // $ target=Outer.Inner.getOuter field=Tuple2.0 type=outer:TOuter
111111
let inner = p.0.getInner() // $ target=Outer.Inner.getInner field=Tuple2.0 type=inner:Int
112112
}
113113
}
114114

115115
class Foo: Outer<String> {
116116
func f(x: Pair, y: Outer<Bool>.Pair) {
117117
var a = x.0.getInner() // $ target=Outer.Inner.getInner field=Tuple2.0 type=a:Int
118-
var b = x.0.getOuter() // $ target=Outer.Inner.getOuter field=Tuple2.0 $ MISSING: type=b:String
118+
var b = x.0.getOuter() // $ target=Outer.Inner.getOuter field=Tuple2.0 $ MISSING: type=b:String -- this is an instance of variance sub typing
119119
var c = y.0.getInner() // $ target=Outer.Inner.getInner field=Tuple2.0 type=c:Int
120-
var d = y.0.getOuter() // $ target=Outer.Inner.getOuter field=Tuple2.0 $ MISSING: type=d:Bool
120+
var d = y.0.getOuter() // $ target=Outer.Inner.getOuter field=Tuple2.0 $ MISSING: type=d:Bool -- this is an instance of variance sub typing
121121
}
122122
}
123123

0 commit comments

Comments
 (0)