Skip to content

Commit 75372e8

Browse files
committed
wip3
1 parent ddae01c commit 75372e8

7 files changed

Lines changed: 161 additions & 98 deletions

File tree

‎unified/ql/lib/codeql/unified/internal/ExprPositions.qll‎

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ private import ExprPositionsPlugin
44

55
/**
66
* Holds if `expr` appears in a context where it must refer to a type,
7-
* and where omission of type arguments implicitly refer to the type
8-
* parameters of the type being accessed (provided that they are in scope).
7+
* based entirely on the syntactic context of the expression.
98
*/
10-
predicate isInTypeContextWithImplicitTypeArgs(Expr expr) {
9+
predicate isInSyntacticTypeContext(Expr expr) {
1110
expr = any(TypeCastExpr n).getType()
1211
or
1312
expr = any(TypeTestExpr n).getType()
@@ -38,26 +37,24 @@ predicate isInTypeContextWithImplicitTypeArgs(Expr expr) {
3837
or
3938
expr.getParent() instanceof TypeConstraint
4039
or
41-
any(ExprPositionsPlugin p).isInTypeContextWithImplicitTypeArgs(expr)
40+
any(ExprPositionsPlugin p).isInSyntacticTypeContext(expr)
4241
or
43-
isInTypeContextWithImplicitTypeArgs(expr.getEnclosingExpr())
42+
isInSyntacticTypeContext(expr.getEnclosingExpr())
4443
}
4544

46-
private predicate isInTypeContextWithoutImplicitTypeArgs(Expr expr) {
45+
private predicate isInTypeContext0(Expr expr) {
4746
exists(NameBinding::getTypeFromRef(expr))
4847
or
49-
any(ExprPositionsPlugin p).isInTypeContext(expr)
50-
or
51-
isInTypeContextWithoutImplicitTypeArgs(expr.getEnclosingExpr())
48+
isInTypeContext0(expr.getEnclosingExpr())
5249
}
5350

5451
/**
5552
* Holds if `expr` appears in a context where it must refer to a type.
5653
*/
5754
predicate isInTypeContext(Expr expr) {
58-
isInTypeContextWithImplicitTypeArgs(expr)
55+
isInSyntacticTypeContext(expr)
5956
or
60-
isInTypeContextWithoutImplicitTypeArgs(expr)
57+
isInTypeContext0(expr)
6158
}
6259

6360
/** Holds if `e` appears in a name-binding position inside `declaration` */

‎unified/ql/lib/codeql/unified/internal/ExprPositionsPlugin.qll‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ private module Plugins {
66
}
77

88
class ExprPositionsPlugin extends Unit {
9-
predicate isInTypeContext(Expr e) { none() }
10-
11-
predicate isInTypeContextWithImplicitTypeArgs(Expr e) { none() }
9+
predicate isInSyntacticTypeContext(Expr e) { none() }
1210

1311
predicate isReturnedExpr(Callable callable, Expr e) { none() }
1412
}

‎unified/ql/lib/codeql/unified/internal/ExprPositionsPluginSwift.qll‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ private import unified
22
private import ExprPositionsPlugin
33

44
private class ExprPositionsPluginSwift extends ExprPositionsPlugin {
5-
override predicate isInTypeContextWithImplicitTypeArgs(Expr e) {
6-
e = any(GenericTypeExpr g).getBase()
7-
}
5+
override predicate isInSyntacticTypeContext(Expr e) { e = any(GenericTypeExpr g).getBase() }
86

97
override predicate isReturnedExpr(Callable callable, Expr e) {
108
// Short-hand return from a function body, e.g. `func foo() -> String { "42" }`

‎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: 89 additions & 77 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+
isInSyntacticTypeContext(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,46 +224,9 @@ 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))
163-
)
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
227+
result = qualifier.getExplicitTypeAt(prefix.appendInverse(suffix))
188228
)
189229
}
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+()
201-
}
202230
}
203231

204232
/**
@@ -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
@@ -244,10 +272,13 @@ class AliasExprTypeMention extends ExprTypeMentionImpl {
244272

245273
override TypeMention getAlias() { result = alias.getType() }
246274

247-
override Type getType() { result = alias.getType().(TypeMention).getType() }
275+
override Type getType() {
276+
result = alias.getType().(TypeMention).getType() and
277+
not result = this.getAliasTypeParameter(_)
278+
}
248279

249280
override Type getTypeAtImpl(TypePath path) {
250-
result = alias.getType().(TypeMention).getTypeAt(path) and
281+
result = alias.getType().(TypeMention).getExplicitTypeAt(path) and
251282
not result = this.getAliasTypeParameter(_)
252283
}
253284
}
@@ -312,7 +343,7 @@ private class NonAliasExprTypeMention extends ExprTypeMentionImpl {
312343
alias = c.getAMember() and
313344
alias.getName() = name and
314345
path = TypePath::cons(baseTp, suffix) and
315-
result = alias.getType().(TypeMention).getTypeAt(suffix)
346+
result = alias.getType().(TypeMention).getExplicitTypeAt(suffix)
316347
)
317348
)
318349
or
@@ -323,40 +354,21 @@ private class NonAliasExprTypeMention extends ExprTypeMentionImpl {
323354
|
324355
exists(int i |
325356
prefix = Plugin::getFunctionExprParameterTypePath(t, fe.getNumberOfParameters(), i) and
326-
result = fe.getParameter(i).getType().(TypeMention).getTypeAt(suffix)
357+
result = fe.getParameter(i).getType().(TypeMention).getExplicitTypeAt(suffix)
327358
)
328359
or
329360
prefix = Plugin::getFunctionExprReturnTypePath(t) and
330-
result = fe.getReturnType().(TypeMention).getTypeAt(suffix)
361+
result = fe.getReturnType().(TypeMention).getExplicitTypeAt(suffix)
331362
)
332363
or
333364
this =
334365
any(TupleExpr te |
335366
exists(Plugin::TupleType tt, int i, TypePath suffix |
336367
tt.getArity() = te.getNumberOfElements() and
337-
result = te.getElement(i).getValue().(TypeMention).getTypeAt(suffix) and
368+
result = te.getElement(i).getValue().(TypeMention).getExplicitTypeAt(suffix) and
338369
path = TypePath::cons(tt.getPositionalTypeParameter(i), suffix)
339370
)
340371
)
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-
)
360372
}
361373

362374
override TypeMention resolve() { result = this }
@@ -379,11 +391,11 @@ private class GenericTypeExprTypeMention extends TypeMentionImpl, GenericTypeExp
379391

380392
pragma[nomagic]
381393
private Type getTypeArgumentAt(int i, TypePath path) {
382-
result = this.getTypeArgument(i).(TypeMention).getTypeAt(path)
394+
result = this.getTypeArgument(i).(TypeMention).getExplicitTypeAt(path)
383395
}
384396

385-
override Type getTypeAt(TypePath path) {
386-
result = base.getTypeAt(path)
397+
override Type getExplicitTypeAt(TypePath path) {
398+
result = base.getExplicitTypeAt(path)
387399
or
388400
base = this.getBase() and
389401
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)