Skip to content

Handling @overload with a docstring declaration #368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
17 changes: 14 additions & 3 deletions pyrefly/lib/binding/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ use crate::types::types::Type;

struct Decorators {
has_no_type_check: bool,
is_overload: bool,
decorators: Box<[Idx<Key>]>,
}

Expand Down Expand Up @@ -398,15 +399,25 @@ impl<'a> BindingsBuilder<'a> {
}

fn decorators(&mut self, decorator_list: Vec<Decorator>, usage: Usage) -> Decorators {
let has_no_type_check = decorator_list
let (is_overload, has_no_type_check) = decorator_list
.iter()
.any(|d| self.as_special_export(&d.expression) == Some(SpecialExport::NoTypeCheck));
.fold((false, false), |(overload, no_check), d| {
if overload && no_check {
return (true, true);
}
let special_export = self.as_special_export(&d.expression);
(
overload || matches!(special_export, Some(SpecialExport::Overload)),
no_check || matches!(special_export, Some(SpecialExport::NoTypeCheck)),
)
});

let decorators = self
.ensure_and_bind_decorators(decorator_list, usage)
.into_boxed_slice();
Decorators {
has_no_type_check,
is_overload,
decorators,
}
}
Expand All @@ -423,7 +434,7 @@ impl<'a> BindingsBuilder<'a> {
function_idx: Idx<KeyFunction>,
class_key: Option<Idx<KeyClass>>,
) -> (FunctionStubOrImpl, Option<SelfAssignments>) {
let stub_or_impl = if is_ellipse(&body) {
let stub_or_impl = if is_ellipse(&body) || (is_docstring(&body[0]) && decorators.is_overload) {
FunctionStubOrImpl::Stub
} else {
FunctionStubOrImpl::Impl
Expand Down
3 changes: 3 additions & 0 deletions pyrefly/lib/export/special.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub enum SpecialExport {
OsExit,
Len,
NoTypeCheck,
Overload,
}

impl SpecialExport {
Expand Down Expand Up @@ -66,6 +67,7 @@ impl SpecialExport {
"_exit" => Some(Self::OsExit),
"len" => Some(Self::Len),
"no_type_check" => Some(Self::NoTypeCheck),
"overload" => Some(Self::Overload),
_ => None,
}
}
Expand All @@ -85,6 +87,7 @@ impl SpecialExport {
| Self::Optional
| Self::AssertType
| Self::NoTypeCheck
| Self::Overload
| Self::Cast => {
matches!(m.as_str(), "typing" | "typing_extensions")
}
Expand Down
45 changes: 45 additions & 0 deletions pyrefly/lib/test/overload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,3 +386,48 @@ def g(x: int):
f(C(x))
"#,
);

testcase!(
test_overload_with_docstring,
r#"
from typing import overload, Any

@overload
def foo(a: int) -> int: ...

@overload
def foo(a: str) -> str:
"""Docstring"""

def foo(*args, **kwargs) -> Any:
pass

"#,
);

testcase!(
test_overload_with_docstring2,
r#"
from typing import overload, Any

@overload
def foo(a: int) -> int: ...

@overload
def foo(a: str) -> str:
"""Docstring"""
return 123 # E: Returned type `Literal[123]` is not assignable to declared return type `str`

def foo(*args, **kwargs) -> Any:
pass

"#,
);

testcase!(
test_overload_with_docstring3,
r#"
def foo() -> int: # E: Function declared to return `int` but is missing an explicit `return`
"""hello"""
"#,
);
Loading