Skip to content

Commit b09a778

Browse files
committed
Rust: Rework type inference for impl Trait in return position
1 parent 04bf2f5 commit b09a778

File tree

5 files changed

+79
-93
lines changed

5 files changed

+79
-93
lines changed

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

Lines changed: 15 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ newtype TType =
1515
TTrait(Trait t) or
1616
TArrayType() or // todo: add size?
1717
TRefType() or // todo: add mut?
18-
TImplTraitType(ImplTraitTypeRepr impl) or
18+
TImplTraitArgumentType(Function function, ImplTraitTypeRepr impl) {
19+
impl = function.getAParam().getTypeRepr()
20+
} or
1921
TSliceType() or
2022
TTypeParamTypeParameter(TypeParam t) or
2123
TAssociatedTypeTypeParameter(TypeAlias t) { any(TraitItemNode trait).getAnAssocItem() = t } or
@@ -196,53 +198,6 @@ class RefType extends Type, TRefType {
196198
override Location getLocation() { result instanceof EmptyLocation }
197199
}
198200

199-
/**
200-
* An [impl Trait][1] type.
201-
*
202-
* Each syntactic `impl Trait` type gives rise to its own type, even if
203-
* two `impl Trait` types have the same bounds.
204-
*
205-
* [1]: https://doc.rust-lang.org/reference/types/impl-trait.html
206-
*/
207-
class ImplTraitType extends Type, TImplTraitType {
208-
ImplTraitTypeRepr impl;
209-
210-
ImplTraitType() { this = TImplTraitType(impl) }
211-
212-
/** Gets the underlying AST node. */
213-
ImplTraitTypeRepr getImplTraitTypeRepr() { result = impl }
214-
215-
/** Gets the function that this `impl Trait` belongs to. */
216-
abstract Function getFunction();
217-
218-
override StructField getStructField(string name) { none() }
219-
220-
override TupleField getTupleField(int i) { none() }
221-
222-
override TypeParameter getTypeParameter(int i) { none() }
223-
224-
override string toString() { result = impl.toString() }
225-
226-
override Location getLocation() { result = impl.getLocation() }
227-
}
228-
229-
/**
230-
* An [impl Trait in return position][1] type, for example:
231-
*
232-
* ```rust
233-
* fn foo() -> impl Trait
234-
* ```
235-
*
236-
* [1]: https://doc.rust-lang.org/reference/types/impl-trait.html#r-type.impl-trait.return
237-
*/
238-
class ImplTraitReturnType extends ImplTraitType {
239-
private Function function;
240-
241-
ImplTraitReturnType() { impl = function.getRetType().getTypeRepr() }
242-
243-
override Function getFunction() { result = function }
244-
}
245-
246201
/**
247202
* A slice type.
248203
*
@@ -386,18 +341,27 @@ class SelfTypeParameter extends TypeParameter, TSelfTypeParameter {
386341
*
387342
* [1]: https://doc.rust-lang.org/reference/types/impl-trait.html#r-type.impl-trait.param
388343
*/
389-
class ImplTraitTypeTypeParameter extends ImplTraitType, TypeParameter {
344+
class ImplTraitArgumentType extends TypeParameter, TImplTraitArgumentType {
390345
private Function function;
346+
private ImplTraitTypeRepr impl;
391347

392-
ImplTraitTypeTypeParameter() { impl = function.getAParam().getTypeRepr() }
348+
ImplTraitArgumentType() { this = TImplTraitArgumentType(function, impl) }
393349

394-
override Function getFunction() { result = function }
350+
/** Gets the function that this `impl Trait` belongs to. */
351+
Function getFunction() { result = function }
352+
353+
/** Gets the underlying AST node. */
354+
ImplTraitTypeRepr getImplTraitTypeRepr() { result = impl }
395355

396356
override StructField getStructField(string name) { none() }
397357

398358
override TupleField getTupleField(int i) { none() }
399359

400360
override TypeParameter getTypeParameter(int i) { none() }
361+
362+
override string toString() { result = impl.toString() }
363+
364+
override Location getLocation() { result = impl.getLocation() }
401365
}
402366

403367
/**

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

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ private module Input1 implements InputSig1<Location> {
100100
node = tp0.(TypeParamTypeParameter).getTypeParam() or
101101
node = tp0.(AssociatedTypeTypeParameter).getTypeAlias() or
102102
node = tp0.(SelfTypeParameter).getTrait() or
103-
node = tp0.(ImplTraitTypeTypeParameter).getImplTraitTypeRepr()
103+
node = tp0.(ImplTraitArgumentType).getImplTraitTypeRepr()
104104
)
105105
|
106106
tp0 order by kind, id
@@ -131,11 +131,7 @@ private module Input2 implements InputSig2 {
131131
result = tp.(SelfTypeParameter).getTrait()
132132
or
133133
result =
134-
tp.(ImplTraitTypeTypeParameter)
135-
.getImplTraitTypeRepr()
136-
.getTypeBoundList()
137-
.getABound()
138-
.getTypeRepr()
134+
tp.(ImplTraitArgumentType).getImplTraitTypeRepr().getTypeBoundList().getABound().getTypeRepr()
139135
}
140136

141137
/**
@@ -612,7 +608,7 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
612608
)
613609
or
614610
ppos.isImplicit() and
615-
this = result.(ImplTraitTypeTypeParameter).getFunction()
611+
this = result.(ImplTraitArgumentType).getFunction()
616612
}
617613

618614
override Type getParameterType(DeclarationPosition dpos, TypePath path) {
@@ -1257,7 +1253,7 @@ private Function getTypeParameterMethod(TypeParameter tp, string name) {
12571253
or
12581254
result = getMethodSuccessor(tp.(SelfTypeParameter).getTrait(), name)
12591255
or
1260-
result = getMethodSuccessor(tp.(ImplTraitTypeTypeParameter).getImplTraitTypeRepr(), name)
1256+
result = getMethodSuccessor(tp.(ImplTraitArgumentType).getImplTraitTypeRepr(), name)
12611257
}
12621258

12631259
pragma[nomagic]
@@ -1427,12 +1423,6 @@ private Function getMethodFromImpl(MethodCall mc) {
14271423
)
14281424
}
14291425

1430-
bindingset[trait, name]
1431-
pragma[inline_late]
1432-
private Function getTraitMethod(ImplTraitReturnType trait, string name) {
1433-
result = getMethodSuccessor(trait.getImplTraitTypeRepr(), name)
1434-
}
1435-
14361426
cached
14371427
private module Cached {
14381428
private import codeql.rust.internal.CachedStages
@@ -1461,6 +1451,12 @@ private module Cached {
14611451
)
14621452
}
14631453

1454+
bindingset[trait, name]
1455+
pragma[inline_late]
1456+
private Function getTraitMethod(TraitType trait, string name) {
1457+
result = getMethodSuccessor(trait.getTrait(), name)
1458+
}
1459+
14641460
/** Gets a method that the method call `mc` resolves to, if any. */
14651461
cached
14661462
Function resolveMethodCallTarget(MethodCall mc) {
@@ -1472,7 +1468,8 @@ private module Cached {
14721468
result = getTypeParameterMethod(mc.getTypeAt(TypePath::nil()), mc.getMethodName())
14731469
or
14741470
// The type of the receiver is an `impl Trait` type.
1475-
result = getTraitMethod(mc.getTypeAt(TypePath::nil()), mc.getMethodName())
1471+
result = getTraitMethod(mc.getTypeAt(TypePath::nil()), mc.getMethodName()) and
1472+
not exists(mc.getTrait())
14761473
}
14771474

14781475
pragma[inline]

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,13 @@ class PathTypeReprMention extends TypeMention, PathTypeRepr {
208208
class ImplTraitTypeReprMention extends TypeMention instanceof ImplTraitTypeRepr {
209209
override Type resolveTypeAt(TypePath typePath) {
210210
typePath.isEmpty() and
211-
result.(ImplTraitType).getImplTraitTypeRepr() = this
211+
result.(ImplTraitArgumentType).getImplTraitTypeRepr() = this
212+
or
213+
exists(Function f |
214+
this = f.getRetType().getTypeRepr() and
215+
result =
216+
super.getTypeBoundList().getABound().getTypeRepr().(TypeMention).resolveTypeAt(typePath)
217+
)
212218
}
213219
}
214220

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1911,7 +1911,7 @@ mod impl_trait {
19111911
let a = get_a_my_trait();
19121912
let c = uses_my_trait2(a); // $ type=c:S2
19131913
let d = uses_my_trait2(S1); // $ type=d:S2
1914-
let e = get_a_my_trait2(S1).get_a(); // $ method=MyTrait::get_a $ MISSING: type=e:S1
1914+
let e = get_a_my_trait2(S1).get_a(); // $ method=MyTrait::get_a $ type=e:S1
19151915
}
19161916
}
19171917

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

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2777,10 +2777,8 @@ inferType
27772777
| main.rs:1811:25:1813:5 | { ... } | | main.rs:1805:5:1805:14 | S1 |
27782778
| main.rs:1812:9:1812:10 | S1 | | main.rs:1805:5:1805:14 | S1 |
27792779
| main.rs:1815:41:1817:5 | { ... } | | {EXTERNAL LOCATION} | trait Future |
2780-
| main.rs:1815:41:1817:5 | { ... } | | main.rs:1815:16:1815:39 | ImplTraitTypeRepr |
27812780
| main.rs:1815:41:1817:5 | { ... } | Output | main.rs:1805:5:1805:14 | S1 |
27822781
| main.rs:1816:9:1816:20 | { ... } | | {EXTERNAL LOCATION} | trait Future |
2783-
| main.rs:1816:9:1816:20 | { ... } | | main.rs:1815:16:1815:39 | ImplTraitTypeRepr |
27842782
| main.rs:1816:9:1816:20 | { ... } | Output | main.rs:1805:5:1805:14 | S1 |
27852783
| main.rs:1816:17:1816:18 | S1 | | main.rs:1805:5:1805:14 | S1 |
27862784
| main.rs:1825:13:1825:42 | SelfParam | | {EXTERNAL LOCATION} | Pin |
@@ -2793,16 +2791,20 @@ inferType
27932791
| main.rs:1828:13:1828:38 | ...::Ready(...) | | {EXTERNAL LOCATION} | Poll |
27942792
| main.rs:1828:13:1828:38 | ...::Ready(...) | T | main.rs:1805:5:1805:14 | S1 |
27952793
| main.rs:1828:36:1828:37 | S1 | | main.rs:1805:5:1805:14 | S1 |
2794+
| main.rs:1832:41:1834:5 | { ... } | | {EXTERNAL LOCATION} | trait Future |
27962795
| main.rs:1832:41:1834:5 | { ... } | | main.rs:1819:5:1819:14 | S2 |
2797-
| main.rs:1832:41:1834:5 | { ... } | | main.rs:1832:16:1832:39 | ImplTraitTypeRepr |
2796+
| main.rs:1832:41:1834:5 | { ... } | Output | main.rs:1805:5:1805:14 | S1 |
2797+
| main.rs:1833:9:1833:10 | S2 | | {EXTERNAL LOCATION} | trait Future |
27982798
| main.rs:1833:9:1833:10 | S2 | | main.rs:1819:5:1819:14 | S2 |
2799-
| main.rs:1833:9:1833:10 | S2 | | main.rs:1832:16:1832:39 | ImplTraitTypeRepr |
2799+
| main.rs:1833:9:1833:10 | S2 | Output | main.rs:1805:5:1805:14 | S1 |
28002800
| main.rs:1837:9:1837:12 | f1(...) | | {EXTERNAL LOCATION} | trait Future |
28012801
| main.rs:1837:9:1837:12 | f1(...) | Output | main.rs:1805:5:1805:14 | S1 |
28022802
| main.rs:1837:9:1837:18 | await ... | | main.rs:1805:5:1805:14 | S1 |
2803-
| main.rs:1838:9:1838:12 | f2(...) | | main.rs:1815:16:1815:39 | ImplTraitTypeRepr |
2803+
| main.rs:1838:9:1838:12 | f2(...) | | {EXTERNAL LOCATION} | trait Future |
2804+
| main.rs:1838:9:1838:12 | f2(...) | Output | main.rs:1805:5:1805:14 | S1 |
28042805
| main.rs:1838:9:1838:18 | await ... | | main.rs:1805:5:1805:14 | S1 |
2805-
| main.rs:1839:9:1839:12 | f3(...) | | main.rs:1832:16:1832:39 | ImplTraitTypeRepr |
2806+
| main.rs:1839:9:1839:12 | f3(...) | | {EXTERNAL LOCATION} | trait Future |
2807+
| main.rs:1839:9:1839:12 | f3(...) | Output | main.rs:1805:5:1805:14 | S1 |
28062808
| main.rs:1839:9:1839:18 | await ... | | main.rs:1805:5:1805:14 | S1 |
28072809
| main.rs:1840:9:1840:10 | S2 | | main.rs:1819:5:1819:14 | S2 |
28082810
| main.rs:1840:9:1840:16 | await S2 | | main.rs:1805:5:1805:14 | S1 |
@@ -2823,9 +2825,11 @@ inferType
28232825
| main.rs:1865:15:1865:19 | SelfParam | | file://:0:0:0:0 | & |
28242826
| main.rs:1865:15:1865:19 | SelfParam | &T | main.rs:1847:5:1848:14 | S1 |
28252827
| main.rs:1868:37:1870:5 | { ... } | | main.rs:1847:5:1848:14 | S1 |
2826-
| main.rs:1868:37:1870:5 | { ... } | | main.rs:1868:16:1868:35 | ImplTraitTypeRepr |
2828+
| main.rs:1868:37:1870:5 | { ... } | | main.rs:1852:5:1854:5 | trait Trait1 |
2829+
| main.rs:1868:37:1870:5 | { ... } | | main.rs:1856:5:1858:5 | trait Trait2 |
28272830
| main.rs:1869:9:1869:10 | S1 | | main.rs:1847:5:1848:14 | S1 |
2828-
| main.rs:1869:9:1869:10 | S1 | | main.rs:1868:16:1868:35 | ImplTraitTypeRepr |
2831+
| main.rs:1869:9:1869:10 | S1 | | main.rs:1852:5:1854:5 | trait Trait1 |
2832+
| main.rs:1869:9:1869:10 | S1 | | main.rs:1856:5:1858:5 | trait Trait2 |
28292833
| main.rs:1873:18:1873:22 | SelfParam | | file://:0:0:0:0 | & |
28302834
| main.rs:1873:18:1873:22 | SelfParam | &T | main.rs:1872:5:1874:5 | Self [trait MyTrait] |
28312835
| main.rs:1877:18:1877:22 | SelfParam | | file://:0:0:0:0 | & |
@@ -2844,15 +2848,19 @@ inferType
28442848
| main.rs:1884:25:1884:28 | self | &T.T3 | main.rs:1882:10:1882:17 | T |
28452849
| main.rs:1885:13:1885:21 | t.clone() | | main.rs:1882:10:1882:17 | T |
28462850
| main.rs:1889:45:1891:5 | { ... } | | main.rs:1847:5:1848:14 | S1 |
2847-
| main.rs:1889:45:1891:5 | { ... } | | main.rs:1889:28:1889:43 | ImplTraitTypeRepr |
2851+
| main.rs:1889:45:1891:5 | { ... } | | main.rs:1872:5:1874:5 | trait MyTrait |
2852+
| main.rs:1889:45:1891:5 | { ... } | A | main.rs:1849:5:1849:14 | S2 |
28482853
| main.rs:1890:9:1890:10 | S1 | | main.rs:1847:5:1848:14 | S1 |
2849-
| main.rs:1890:9:1890:10 | S1 | | main.rs:1889:28:1889:43 | ImplTraitTypeRepr |
2854+
| main.rs:1890:9:1890:10 | S1 | | main.rs:1872:5:1874:5 | trait MyTrait |
2855+
| main.rs:1890:9:1890:10 | S1 | A | main.rs:1849:5:1849:14 | S2 |
28502856
| main.rs:1893:34:1893:34 | x | | main.rs:1893:24:1893:31 | T |
28512857
| main.rs:1893:59:1895:5 | { ... } | | main.rs:1850:5:1850:22 | S3 |
2852-
| main.rs:1893:59:1895:5 | { ... } | | main.rs:1893:43:1893:57 | ImplTraitTypeRepr |
2858+
| main.rs:1893:59:1895:5 | { ... } | | main.rs:1872:5:1874:5 | trait MyTrait |
2859+
| main.rs:1893:59:1895:5 | { ... } | A | main.rs:1893:24:1893:31 | T |
28532860
| main.rs:1893:59:1895:5 | { ... } | T3 | main.rs:1893:24:1893:31 | T |
28542861
| main.rs:1894:9:1894:13 | S3(...) | | main.rs:1850:5:1850:22 | S3 |
2855-
| main.rs:1894:9:1894:13 | S3(...) | | main.rs:1893:43:1893:57 | ImplTraitTypeRepr |
2862+
| main.rs:1894:9:1894:13 | S3(...) | | main.rs:1872:5:1874:5 | trait MyTrait |
2863+
| main.rs:1894:9:1894:13 | S3(...) | A | main.rs:1893:24:1893:31 | T |
28562864
| main.rs:1894:9:1894:13 | S3(...) | T3 | main.rs:1893:24:1893:31 | T |
28572865
| main.rs:1894:12:1894:12 | x | | main.rs:1893:24:1893:31 | T |
28582866
| main.rs:1897:41:1897:41 | t | | main.rs:1897:26:1897:38 | B |
@@ -2863,26 +2871,37 @@ inferType
28632871
| main.rs:1901:51:1903:5 | { ... } | | main.rs:1901:23:1901:23 | A |
28642872
| main.rs:1902:9:1902:9 | t | | main.rs:1901:29:1901:43 | ImplTraitTypeRepr |
28652873
| main.rs:1902:9:1902:17 | t.get_a() | | main.rs:1901:23:1901:23 | A |
2866-
| main.rs:1906:13:1906:13 | x | | main.rs:1868:16:1868:35 | ImplTraitTypeRepr |
2867-
| main.rs:1906:17:1906:20 | f1(...) | | main.rs:1868:16:1868:35 | ImplTraitTypeRepr |
2868-
| main.rs:1907:9:1907:9 | x | | main.rs:1868:16:1868:35 | ImplTraitTypeRepr |
2869-
| main.rs:1908:9:1908:9 | x | | main.rs:1868:16:1868:35 | ImplTraitTypeRepr |
2870-
| main.rs:1909:13:1909:13 | a | | main.rs:1889:28:1889:43 | ImplTraitTypeRepr |
2871-
| main.rs:1909:17:1909:32 | get_a_my_trait(...) | | main.rs:1889:28:1889:43 | ImplTraitTypeRepr |
2874+
| main.rs:1906:13:1906:13 | x | | main.rs:1852:5:1854:5 | trait Trait1 |
2875+
| main.rs:1906:13:1906:13 | x | | main.rs:1856:5:1858:5 | trait Trait2 |
2876+
| main.rs:1906:17:1906:20 | f1(...) | | main.rs:1852:5:1854:5 | trait Trait1 |
2877+
| main.rs:1906:17:1906:20 | f1(...) | | main.rs:1856:5:1858:5 | trait Trait2 |
2878+
| main.rs:1907:9:1907:9 | x | | main.rs:1852:5:1854:5 | trait Trait1 |
2879+
| main.rs:1907:9:1907:9 | x | | main.rs:1856:5:1858:5 | trait Trait2 |
2880+
| main.rs:1908:9:1908:9 | x | | main.rs:1852:5:1854:5 | trait Trait1 |
2881+
| main.rs:1908:9:1908:9 | x | | main.rs:1856:5:1858:5 | trait Trait2 |
2882+
| main.rs:1909:13:1909:13 | a | | main.rs:1872:5:1874:5 | trait MyTrait |
2883+
| main.rs:1909:13:1909:13 | a | A | main.rs:1849:5:1849:14 | S2 |
2884+
| main.rs:1909:17:1909:32 | get_a_my_trait(...) | | main.rs:1872:5:1874:5 | trait MyTrait |
2885+
| main.rs:1909:17:1909:32 | get_a_my_trait(...) | A | main.rs:1849:5:1849:14 | S2 |
28722886
| main.rs:1910:13:1910:13 | b | | main.rs:1849:5:1849:14 | S2 |
28732887
| main.rs:1910:17:1910:33 | uses_my_trait1(...) | | main.rs:1849:5:1849:14 | S2 |
2874-
| main.rs:1910:32:1910:32 | a | | main.rs:1889:28:1889:43 | ImplTraitTypeRepr |
2875-
| main.rs:1911:13:1911:13 | a | | main.rs:1889:28:1889:43 | ImplTraitTypeRepr |
2876-
| main.rs:1911:17:1911:32 | get_a_my_trait(...) | | main.rs:1889:28:1889:43 | ImplTraitTypeRepr |
2888+
| main.rs:1910:32:1910:32 | a | | main.rs:1872:5:1874:5 | trait MyTrait |
2889+
| main.rs:1910:32:1910:32 | a | A | main.rs:1849:5:1849:14 | S2 |
2890+
| main.rs:1911:13:1911:13 | a | | main.rs:1872:5:1874:5 | trait MyTrait |
2891+
| main.rs:1911:13:1911:13 | a | A | main.rs:1849:5:1849:14 | S2 |
2892+
| main.rs:1911:17:1911:32 | get_a_my_trait(...) | | main.rs:1872:5:1874:5 | trait MyTrait |
2893+
| main.rs:1911:17:1911:32 | get_a_my_trait(...) | A | main.rs:1849:5:1849:14 | S2 |
28772894
| main.rs:1912:13:1912:13 | c | | main.rs:1849:5:1849:14 | S2 |
28782895
| main.rs:1912:17:1912:33 | uses_my_trait2(...) | | main.rs:1849:5:1849:14 | S2 |
2879-
| main.rs:1912:32:1912:32 | a | | main.rs:1889:28:1889:43 | ImplTraitTypeRepr |
2896+
| main.rs:1912:32:1912:32 | a | | main.rs:1872:5:1874:5 | trait MyTrait |
2897+
| main.rs:1912:32:1912:32 | a | A | main.rs:1849:5:1849:14 | S2 |
28802898
| main.rs:1913:13:1913:13 | d | | main.rs:1849:5:1849:14 | S2 |
28812899
| main.rs:1913:17:1913:34 | uses_my_trait2(...) | | main.rs:1849:5:1849:14 | S2 |
28822900
| main.rs:1913:32:1913:33 | S1 | | main.rs:1847:5:1848:14 | S1 |
2883-
| main.rs:1914:13:1914:13 | e | | main.rs:1893:24:1893:31 | T |
2884-
| main.rs:1914:17:1914:35 | get_a_my_trait2(...) | | main.rs:1893:43:1893:57 | ImplTraitTypeRepr |
2885-
| main.rs:1914:17:1914:43 | ... .get_a() | | main.rs:1893:24:1893:31 | T |
2901+
| main.rs:1914:13:1914:13 | e | | main.rs:1847:5:1848:14 | S1 |
2902+
| main.rs:1914:17:1914:35 | get_a_my_trait2(...) | | main.rs:1872:5:1874:5 | trait MyTrait |
2903+
| main.rs:1914:17:1914:35 | get_a_my_trait2(...) | A | main.rs:1847:5:1848:14 | S1 |
2904+
| main.rs:1914:17:1914:43 | ... .get_a() | | main.rs:1847:5:1848:14 | S1 |
28862905
| main.rs:1914:33:1914:34 | S1 | | main.rs:1847:5:1848:14 | S1 |
28872906
| main.rs:1925:16:1925:20 | SelfParam | | file://:0:0:0:0 | & |
28882907
| main.rs:1925:16:1925:20 | SelfParam | &T | main.rs:1921:5:1922:13 | S |

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy