Skip to content

Commit f1135bb

Browse files
martindemellometa-codesync[bot]
authored andcommitted
Minor refactoring to qualified name resolution
Reviewed By: mpage Differential Revision: D96363333 fbshipit-source-id: c0d4a17c322c8136c97d3ca078122cbf10e8f388
1 parent 1b419c5 commit f1135bb

1 file changed

Lines changed: 52 additions & 49 deletions

File tree

cinderx/PythonLib/cinderx/compiler/static/pyrefly_info.py

Lines changed: 52 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -176,77 +176,80 @@ def load_json(cls, json_path: str) -> PyreflyTypeInfo:
176176
data = json.load(f)
177177
return cls(data)
178178

179-
def resolve_func(
179+
def _resolve_qname(
180180
self,
181181
qname: str,
182182
modules: dict[str, ModuleTable],
183-
type_env: TypeEnvironment,
184-
) -> Value | None:
185-
"""Resolve a dotted qname like 'module.path.func_name' to a callable Value.
183+
) -> tuple[str, Value, list[str]] | None:
184+
"""Resolve a dotted qname into a top-level value and a chain of attributes.
186185
187186
Splits the qname on '.' and tries progressively shorter prefixes
188-
as module names, then looks up the function name in the module.
189-
This handles both user-defined Functions and built-in callable
190-
types like LenFunction.
187+
as module names, then looks up the next name in the chain as a
188+
top-level value in that module. Returns the module name, the top-level
189+
value, and the remaining attributes, e.g. if foo.bar.baz is a module,
190+
_resolve_qname("foo.bar.baz.A.B.f") ->
191+
("foo.bar.baz", foo.bar.baz.A, ["B", "f"])
191192
"""
192193
parts = qname.split(".")
193-
194194
for i in range(len(parts) - 1, 0, -1):
195195
mod_name = ".".join(parts[:i])
196196
if mod_name in modules:
197197
mod = modules[mod_name]
198198
result = mod.get_child(parts[i], mod_name)
199-
if result is None:
200-
continue
201-
# Walk remaining parts (e.g. Class.method)
202-
for part in parts[i + 1 :]:
203-
if isinstance(result, Class):
204-
result = result.get_member(part)
205-
else:
206-
result = None
207-
break
208-
if result is None:
209-
break
210199
if result is not None:
211-
return result
200+
return mod_name, result, parts[i + 1 :]
201+
return None
202+
203+
def resolve_func(
204+
self,
205+
qname: str,
206+
modules: dict[str, ModuleTable],
207+
type_env: TypeEnvironment,
208+
) -> Value | None:
209+
"""Resolve a dotted qname like 'module.path.func_name' to a callable Value.
210+
211+
This handles both user-defined Functions and built-in callable
212+
types like LenFunction.
213+
"""
214+
if ret := self._resolve_qname(qname, modules):
215+
_, result, parts = ret
216+
else:
217+
return None
218+
for part in parts:
219+
if isinstance(result, Class):
220+
result = result.get_member(part)
221+
else:
222+
result = None
223+
if result is None:
224+
break
225+
if result is not None:
226+
return result
212227

213228
return None
214229

215230
def resolve_classname(
216231
self, qname: str, modules: dict[str, ModuleTable], type_env: TypeEnvironment
217232
) -> Class | None:
218-
"""Resolve a dotted qname like 'builtins.int' to a Class.
219-
220-
Splits the qname on '.' and tries progressively shorter prefixes
221-
as module names, then walks the remainder as nested attributes.
222-
"""
223-
parts = qname.split(".")
224-
225-
# Try progressively shorter prefixes as module names
226-
for i in range(len(parts) - 1, 0, -1):
227-
mod_name = ".".join(parts[:i])
228-
if mod_name in modules:
229-
mod = modules[mod_name]
230-
result = mod.get_child(parts[i], mod_name)
231-
if result is None:
232-
continue
233-
# Walk any remaining parts (e.g. nested classes)
234-
for part in parts[i + 1 :]:
235-
if isinstance(result, Class):
236-
# pyre-ignore[16]: `Class` has no attribute `get_child`
237-
result = result.get_child(part, mod_name)
238-
else:
239-
return None
240-
if result is None:
241-
return None
233+
"""Resolve a dotted qname like 'builtins.int' to a Class."""
234+
if ret := self._resolve_qname(qname, modules):
235+
mod_name, result, parts = ret
236+
# Walk any remaining parts (e.g. nested classes)
237+
for part in parts:
242238
if isinstance(result, Class):
243-
return result.inexact_type()
244-
elif isinstance(result, Value):
245-
return result.klass
246-
return None
239+
# pyre-ignore[16]: `Class` has no attribute `get_child`
240+
result = result.get_child(part, mod_name)
241+
else:
242+
return None
243+
if result is None:
244+
return None
245+
if isinstance(result, Class):
246+
return result.inexact_type()
247+
elif isinstance(result, Value):
248+
return result.klass
249+
return None
247250

248251
# No dot — try builtins
249-
if len(parts) == 1:
252+
if "." not in qname:
250253
builtins = modules.get("builtins")
251254
if builtins is not None:
252255
result = builtins.get_child(parts[0], "builtins")

0 commit comments

Comments
 (0)