1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! `::`-delimited path containment and leaf/self-type helpers shared by every capability's
//! subtree / forbidden / allowed test — the single home of the containment rule, so no copy
//! drifts to a bare `starts_with` that would admit a sibling (a false positive on the allowed
//! side, a false negative on the forbidden side). Name resolution itself lives in
//! [`crate::resolve`].
use HashSet;
use crate;
/// Sibling-safe `::`-path containment: `path` equals `prefix` or sits strictly beneath it
/// (`crate::a` contains `crate::a::b`, never the sibling `crate::ab`). (The module doc carries the
/// why — single home, no bare `starts_with`.)
/// A canonical path is under `subtree` — [`path_within`] read with subtree-containment naming at
/// the call site (`crate::a` contains `crate::a::b`, never the sibling `crate::ab`).
pub
/// The leaf identifier of a `::`-delimited path string, raw-canonicalized (`r#Trait` → `Trait`) so
/// a declared marker written with a raw identifier compares equal to the observed [`path_leaf`],
/// which strips it. (Trait names are never keywords, so this is defensive symmetry, not a live gap.)
pub
/// The leaf identifier of a `syn::Path` (raw-canonicalized).
pub
/// Resolve an `impl`'s self-type to the canonical path of the type it **lands on** — its
/// definition — or `None` when it is not a placeable nominal path (a reference/tuple/complex
/// shape — a stated bound). For a `Type::Path` (incl. a generic `Wrapper<T>`, governed by the
/// outer `Wrapper`), the leading path resolves via the impl module's `use`s / current-module,
/// then is followed through the re-export (`pub use` facade) and type-alias closures to the
/// definition it denotes: `impl M for crate::facade::T` where `crate::facade` re-exports `T`, and
/// `impl M for Bar` where `type Bar = Real`, both land on the real definition (to coherence a
/// re-export/alias denotes the same type, so the marker genuinely lands there).
///
/// `impl_type_params` shadows the impl block's OWN declared generic type-parameter names
/// (`impl<T> Marker for T {}`'s `T`), the identical shadowing the exposure collectors already
/// apply ([`crate::collect::exposure::type_param_names`]) for every OTHER impl-site position — see
/// `semantic-forbidden-marker`'s "Anchor resolution and observation bounds" requirement (the
/// blanket-impl/projection/qualified-path shadow scenarios) for the full rationale. Without the
/// shadow, a blanket `impl<T> Marker for T {}` beside an unrelated `use
/// crate::domain::Innocent as T;` fabricated a marker-acquisition finding on `Innocent`, which the
/// source never actually impls the marker for.
///
/// The canonicalization is folded in **here** so a self-type is canonical *by construction*: a
/// caller cannot resolve a self-type and forget to close the re-export/alias hop (the sibling
/// capabilities' shared-canonicalizer discipline, made structural at the one self-type resolver).
/// Routed through the crate's own [`expand_canonical_paths`] rather than a second hand-rolled
/// fixpoint, so this resolver shares that function's hop cap (bounding a divergent, non-cycling
/// rewrite chain that an exact-repeat guard alone cannot catch — a gap a hand-rolled loop here once
/// had) and its longest-prefix alias rewrite (so a member reached *through* an aliased prefix, not
/// just an exact alias key, still lands — closing a second, narrower false negative the same swap
/// fixed). `alias_targets` carries the `CurrentModule`-fallback landing, so an alias to a bare local
/// struct (`type Bar = Real`) is caught — which the `Ignore`-built exposure alias map deliberately
/// does not, the reason this is not the exposure canonicalizer. A defining path is never a key in
/// either map (an alias/re-export name cannot clash with a definition in its module), so the
/// fixpoint never over-follows past a definition.
///
/// Returns **every** landing candidate, cfg-blind like the exposure pipeline's own
/// `expand_canonical_paths`: a self type whose head, or whose `type X = Y;` alias target, is a
/// mutually-exclusive `#[cfg]`-gated `use` name must not have its other candidate silently
/// dropped (found on adversarial review of `hunyi-cfg-branch-use-reexport-merging`: the
/// marker-acquisition self-type landing missed a forbidden self type this way).
pub
/// `::`-delimited containment: a canonical path is forbidden when it equals a forbidden
/// entry or sits beneath it (so `crate::infra` matches `crate::infra::db::Pool` but never
/// the sibling `crate::infrastructure`).
pub
/// `::`-delimited containment at allowed-vs-location polarity: a module location is
/// allowed when it equals an allowed entry or sits beneath it (so `crate::commands`
/// allows `crate::commands::greet` but never the sibling `crate::commandeer`).
pub