MCPcopy Create free account
hub / github.com/PHPantom-dev/phpantom_lsp / build_substitution_map

Function build_substitution_map

src/inheritance.rs:1149–1200  ·  view source on GitHub ↗

Build a substitution map for a parent class based on the child's `@extends` generics and the parent's `@template` parameters. If the child declares `@extends Collection ` and the parent `Collection` has `@template TKey` and `@template TValue`, the returned map is `{TKey => int, TValue => Language}`. When `active_subs` is non-empty (from a higher-level ancestor), the type arguments

(
    current: &ClassInfo,
    parent: &ClassInfo,
    active_subs: &HashMap<String, PhpType>,
)

Source from the content-addressed store, hash-verified

1147/// `@extends A<T>` gets the active substitution `{T => Foo}` applied,
1148/// yielding `{U => Foo}`.
1149fn build_substitution_map(
1150 current: &ClassInfo,
1151 parent: &ClassInfo,
1152 active_subs: &HashMap<String, PhpType>,
1153) -> HashMap<String, PhpType> {
1154 if parent.template_params.is_empty() {
1155 return active_subs.clone();
1156 }
1157
1158 let parent_short = short_name(&parent.name);
1159
1160 // Search `current.extends_generics` for an entry matching this parent.
1161 // Also check `implements_generics` for interface inheritance.
1162 let type_args = current
1163 .extends_generics
1164 .iter()
1165 .chain(current.implements_generics.iter())
1166 .find(|(name, _)| {
1167 let name_short = short_name(name);
1168 name_short == parent_short
1169 })
1170 .map(|(_, args)| args);
1171
1172 let type_args = match type_args {
1173 Some(args) => args,
1174 None => {
1175 // No @extends/@implements generics for this parent.
1176 // Carry forward any active substitutions — they may still
1177 // apply if the parent's methods reference template params
1178 // from a grandchild.
1179 return active_subs.clone();
1180 }
1181 };
1182
1183 let mut map = HashMap::new();
1184
1185 for (i, param_name) in parent.template_params.iter().enumerate() {
1186 if let Some(arg) = type_args.get(i) {
1187 // Apply any active substitutions to the type argument.
1188 // This handles chaining: if arg is "T" and active_subs has
1189 // {T => Foo}, the result is {param_name => Foo}.
1190 let resolved = if active_subs.is_empty() {
1191 arg.clone()
1192 } else {
1193 arg.substitute(active_subs)
1194 };
1195 map.insert(param_name.to_string(), resolved);
1196 }
1197 }
1198
1199 map
1200}
1201
1202/// Apply generic type substitution to a method's return type and parameter
1203/// type hints.

Calls 9

cloneMethod · 0.80
iterMethod · 0.80
substituteMethod · 0.80
short_nameFunction · 0.70
is_emptyMethod · 0.45
mapMethod · 0.45
findMethod · 0.45
getMethod · 0.45
insertMethod · 0.45