Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions nominal_refactor_advisor/captured_reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,14 @@
from .value_expression import LexicalValueReference, TargetResolutionT

if TYPE_CHECKING:
from .native_compilation import NativeProducedValue, NativeTupleValue, NativeListValue
from .native_call import CallAuthority, NativeDefinitionApplicationAuthorityABC
from .native_reference import NativeReferenceEnvironment
from .source_entry import SourceModuleEntryPremise
from .source_execution import (
SourceDefinitionDecoratorApplicationABC,
SourceFunctionActivationABC,
SourceNativeExpressionABC,
)


Expand Down Expand Up @@ -124,6 +126,22 @@ def __init__(self, evidence: OpenCapturedReference, query: str) -> None:

class CapturedReferenceResolution(NativeScalarValueABC):

def require_native_function_operand(self, value: NativeProducedValue) -> None:
self.require_closed()
raise ValueError("Native function requires original source creation evidence")

def require_native_tuple_operand(
self, value: NativeTupleValue, source: SourceNativeExpressionABC
) -> None:
self.require_closed()
raise ValueError("Native tuple requires an original source tuple construction")

def require_native_list_operand(
self, value: NativeListValue, source: SourceNativeExpressionABC
) -> None:
self.require_closed()
raise ValueError("Native list requires its original literal construction")

def require_dictionary_key(self) -> NativeDictionaryKey:
"""Scalar contents supply a key; other identities need their own evidence."""
return self.require_native_scalar()
Expand Down
70 changes: 62 additions & 8 deletions nominal_refactor_advisor/lexical_bindings.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from enum import StrEnum
from functools import cached_property
from typing import (
TYPE_CHECKING,
ClassVar,
Generic,
Self,
Expand All @@ -27,6 +28,9 @@
)
from .python_module_identity import PythonModulePathIdentity

if TYPE_CHECKING:
from .native_compilation import NativeParameterDefaultOperand, NativeProducedValue


class CompactParameterKind(StrEnum):
"""Python parameter kinds with their binding behavior on each member."""
Expand Down Expand Up @@ -130,30 +134,40 @@ def from_arguments(
) -> tuple[FunctionParameterSource, ...]:
positional = (*arguments.posonlyargs, *arguments.args)
undefaulted = len(positional) - len(arguments.defaults)
defaults: dict[ast.arg, ast.expr] = dict(
zip(positional[undefaulted:], arguments.defaults, strict=True)
)
parameters = FunctionArgumentSource.from_arguments(arguments)
by_argument = {parameter.argument: parameter for parameter in parameters}
defaults: dict[ast.arg, DefaultedParameterSource] = {
argument: PositionalDefaultedParameterSource(
argument, by_argument[argument].kind, default
)
for argument, default in zip(
positional[undefaulted:], arguments.defaults, strict=True
)
}
defaults.update(
(argument, default)
(argument, KeywordDefaultedParameterSource(
argument, by_argument[argument].kind, default
))
for argument, default in zip(
arguments.kwonlyargs, arguments.kw_defaults, strict=True
)
# The ast boundary: a keyword-only parameter without a default holds None.
if default is not None
)
return tuple(
DefaultedParameterSource(
parameter.argument, parameter.kind, defaults[parameter.argument]
)
defaults[parameter.argument]
if parameter.argument in defaults
else UndefaultedParameterSource(parameter.argument, parameter.kind)
for parameter in FunctionArgumentSource.from_arguments(arguments)
for parameter in parameters
)

@abstractmethod
def answer(self, question: ParameterDefaultQuestion[DefaultAnswerT]) -> DefaultAnswerT:
raise NotImplementedError

def declares_default(self, source: DefaultedParameterSource) -> bool:
return False


@dataclass(frozen=True)
class DefaultedParameterSource(FunctionParameterSource):
Expand All @@ -164,6 +178,46 @@ class DefaultedParameterSource(FunctionParameterSource):
def answer(self, question: ParameterDefaultQuestion[DefaultAnswerT]) -> DefaultAnswerT:
return question.defaulted(self)

def declares_default(self, source: DefaultedParameterSource) -> bool:
return (
self.argument is source.argument
and self.kind is source.kind
and self.default is source.default
)

def native_default_operand(
self, function: NativeProducedValue
) -> NativeParameterDefaultOperand:
candidates = tuple(
operand
for operand in self._native_default_operands(function)
if operand.parameter_name == self.argument.arg
)
if len(candidates) != 1:
raise ValueError("Source default has no unique original native slot")
return candidates[0]

@abstractmethod
def _native_default_operands(
self, function: NativeProducedValue
) -> tuple[NativeParameterDefaultOperand, ...]:
"""Select this source storage shape, not a runtime default object."""
raise NotImplementedError


class PositionalDefaultedParameterSource(DefaultedParameterSource):
def _native_default_operands(
self, function: NativeProducedValue
) -> tuple[NativeParameterDefaultOperand, ...]:
return function.positional_default_operands()


class KeywordDefaultedParameterSource(DefaultedParameterSource):
def _native_default_operands(
self, function: NativeProducedValue
) -> tuple[NativeParameterDefaultOperand, ...]:
return function.keyword_default_operands()


@dataclass(frozen=True)
class UndefaultedParameterSource(FunctionParameterSource):
Expand Down
Loading
Loading