@@ -760,6 +760,59 @@ call_site_unresolved(site, caller, r, kind) :-
760760 site_class(site, "ambiguous_unknown"), site_caller(site, caller),
761761 site_reason(site, r), invocation_site(site, kind).
762762
763+ // ── unresolved_value_callee(SiteKey, Binding) ────────────────────────────────
764+ // An unresolved call whose callee is a VALUE, not a name: `cb()` on a parameter, `f()`
765+ // on a loop or comprehension variable, `table[k]()`, `hook()` on what getattr returned,
766+ // `self.cb()` on a function stored in a field. Nothing about the name narrows what it
767+ // calls, so a question that finds no chain from its caller must answer "unknown", never
768+ // "independent" (the same relation, and the same Binding words, as the JavaScript rules).
769+ // A call on an untyped receiver (`obj.save()`) is not one: its name is the lead the
770+ // by-name search follows.
771+ // `cls(...)` in a classmethod constructs the class or a subclass of it, never an arbitrary
772+ // function, so it is not one.
773+ value_callee_site(site, c) :-
774+ site_class(site, "ambiguous_unknown"), call_callee_is_value(site), call_callee_expr(site, c),
775+ !expr_node("client", "CLS_REFERENCE", _, _, c).
776+ value_callee_binding(site, origin, kind, b2) :-
777+ value_callee_site(site, c), expr_binding("client", b, ctx, c), ctx != "STORE",
778+ binding_lookup("client", b, b2), binding_decl("client", _, _, kind, origin, b2).
779+ // what a local was assigned, when that is a getattr call: the attribute is picked by a
780+ // name the program computes
781+ value_callee_from_getattr(site) :-
782+ value_callee_binding(site, _, _, b2), expr_binding("client", b2, "STORE", tgt),
783+ assign_pair("client", tgt, val), call_of_expr(val, g), call_name(g, "getattr").
784+ value_callee_from_getattr(site) :-
785+ value_callee_site(site, c), call_of_expr(c, g), call_name(g, "getattr").
786+ unresolved_value_callee(site, "getattr") :- value_callee_from_getattr(site).
787+ unresolved_value_callee(site, "parameter") :-
788+ value_callee_binding(site, origin, _, _), (origin = "PARAMETER" ; origin = "LAMBDA_PARAM").
789+ unresolved_value_callee(site, "loop_variable") :-
790+ value_callee_binding(site, origin, _, _), (origin = "FOR_TARGET" ; origin = "COMPREHENSION_TARGET").
791+ value_callee_names_value(origin) :- binding_decl("client", _, _, _, origin, _),
792+ origin != "PARAMETER", origin != "LAMBDA_PARAM", origin != "FOR_TARGET", origin != "COMPREHENSION_TARGET",
793+ origin != "FUNCTION_DEF", origin != "CLASS_DEF", origin != "IMPORT", origin != "TYPE_PARAM",
794+ origin != "TYPE_ALIAS", origin != "MULTIPLE".
795+ unresolved_value_callee(site, "local") :-
796+ value_callee_binding(site, origin, "LOCAL", _), value_callee_names_value(origin),
797+ !value_callee_from_getattr(site).
798+ unresolved_value_callee(site, "module_variable") :-
799+ value_callee_binding(site, origin, kind, _), kind != "LOCAL", value_callee_names_value(origin),
800+ !value_callee_from_getattr(site).
801+ // `table[k]()`: an element of a collection
802+ unresolved_value_callee(site, "computed") :-
803+ value_callee_site(site, c), expr_node("client", "SUBSCRIPT", _, _, c).
804+ // `make()()`, `(a or b)()`: the callee is what an expression evaluates to
805+ unresolved_value_callee(site, "expression") :-
806+ value_callee_site(site, c), expr_node("client", k, _, _, c),
807+ k != "NAME_REFERENCE", k != "SUBSCRIPT", k != "CLS_REFERENCE", k != "ATTRIBUTE_ACCESS",
808+ !value_callee_from_getattr(site).
809+ // `self.cb()` where the class gives `cb` a field and no method: the function stored
810+ // there is whatever the constructor or a setter was handed
811+ unresolved_value_callee(site, "field") :-
812+ site_class(site, "ambiguous_unknown"), invocation_site(site, "SELF_CALL"),
813+ call_name(site, n), call_enclosing_type(site, t),
814+ type_defines_field("client", t, n, _), !mro_lookup("client", t, n, _).
815+
763816// ── method_has_unknown_call(CallerMethodHash, SiteKey) ───────────────────────
764817method_has_unknown_call(caller, site) :-
765818 site_class(site, "ambiguous_unknown"), site_caller(site, caller).
0 commit comments