Skip to content

Commit f4703c4

Browse files
change include
1 parent 8e9276f commit f4703c4

File tree

3 files changed

+65
-6
lines changed

3 files changed

+65
-6
lines changed

pyrefly/lib/binding/scope.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use parse_display::Display;
1616
use pyrefly_python::ast::Ast;
1717
use pyrefly_python::dunder;
1818
use pyrefly_python::module_name::ModuleName;
19+
use pyrefly_python::module_path::ModulePathDetails;
1920
use pyrefly_python::nesting_context::NestingContext;
2021
use pyrefly_python::short_identifier::ShortIdentifier;
2122
use pyrefly_python::sys_info::SysInfo;
@@ -390,11 +391,18 @@ impl Static {
390391
get_annotation_idx: &mut impl FnMut(ShortIdentifier) -> Idx<KeyAnnotation>,
391392
scopes: Option<&Scopes>,
392393
) {
394+
let include_unreachable_defs = matches!(
395+
module_info.path().details(),
396+
ModulePathDetails::FileSystem(_) | ModulePathDetails::Memory(_)
397+
) && module_info.name() != ModuleName::builtins()
398+
&& module_info.name() != ModuleName::extra_builtins();
399+
393400
let mut d = Definitions::new(
394401
x,
395402
module_info.name(),
396403
module_info.path().is_init(),
397404
sys_info,
405+
include_unreachable_defs,
398406
);
399407
if top_level {
400408
if module_info.name() != ModuleName::builtins() {

pyrefly/lib/export/definitions.rs

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ struct DefinitionsBuilder<'a> {
211211
module_name: ModuleName,
212212
is_init: bool,
213213
sys_info: &'a SysInfo,
214+
include_unreachable: bool,
214215
reachability: Reachability,
215216
inner: Definitions,
216217
}
@@ -238,11 +239,18 @@ fn is_overload_decorator(decorator: &Decorator) -> bool {
238239
}
239240

240241
impl Definitions {
241-
pub fn new(x: &[Stmt], module_name: ModuleName, is_init: bool, sys_info: &SysInfo) -> Self {
242+
pub fn new(
243+
x: &[Stmt],
244+
module_name: ModuleName,
245+
is_init: bool,
246+
sys_info: &SysInfo,
247+
include_unreachable: bool,
248+
) -> Self {
242249
let mut builder = DefinitionsBuilder {
243250
module_name,
244251
sys_info,
245252
is_init,
253+
include_unreachable,
246254
reachability: Reachability::Reachable,
247255
inner: Definitions::default(),
248256
};
@@ -663,20 +671,24 @@ impl<'a> DefinitionsBuilder<'a> {
663671
}
664672
}
665673
Stmt::If(x) => {
666-
self.named_in_expr(&x.test);
667-
let mut seen_definitely_true = false;
668674
for (test, body) in Ast::if_branches(x) {
675+
if let Some(test_expr) = test {
676+
self.named_in_expr(test_expr);
677+
}
669678
let evaluation = test
670679
.map(|expr| self.sys_info.evaluate_bool(expr))
671680
.unwrap_or(Some(true));
672-
let branch_reachability = if seen_definitely_true || evaluation == Some(false) {
681+
if evaluation == Some(false) && !self.include_unreachable {
682+
continue;
683+
}
684+
let branch_reachability = if evaluation == Some(false) {
673685
Reachability::Unreachable
674686
} else {
675687
Reachability::Reachable
676688
};
677689
self.with_reachability(branch_reachability, |builder| builder.stmts(body));
678690
if evaluation == Some(true) {
679-
seen_definitely_true = true;
691+
break; // Later branches are not evaluated in this configuration
680692
}
681693
}
682694
return; // We went through the relevant branches already
@@ -775,25 +787,44 @@ mod tests {
775787
}
776788
}
777789

778-
fn calculate_unranged_definitions(
790+
fn calculate_unranged_definitions_with_config(
779791
contents: &str,
780792
module_name: ModuleName,
781793
is_init: bool,
794+
include_unreachable: bool,
782795
) -> Definitions {
783796
let mut res = Definitions::new(
784797
&Ast::parse(contents, PySourceType::Python).0.body,
785798
module_name,
786799
is_init,
787800
&SysInfo::default(),
801+
include_unreachable,
788802
);
789803
res.dunder_all.iter_mut().for_each(unrange);
790804
res
791805
}
792806

807+
fn calculate_unranged_definitions(
808+
contents: &str,
809+
module_name: ModuleName,
810+
is_init: bool,
811+
) -> Definitions {
812+
calculate_unranged_definitions_with_config(contents, module_name, is_init, false)
813+
}
814+
793815
fn calculate_unranged_definitions_with_defaults(contents: &str) -> Definitions {
794816
calculate_unranged_definitions(contents, ModuleName::from_str("main"), false)
795817
}
796818

819+
fn calculate_unranged_definitions_with_unreachable(contents: &str) -> Definitions {
820+
calculate_unranged_definitions_with_config(
821+
contents,
822+
ModuleName::from_str("main"),
823+
false,
824+
true,
825+
)
826+
}
827+
797828
fn assert_import_all(defs: &Definitions, expected_import_all: &[&str]) {
798829
assert_eq!(
799830
expected_import_all,
@@ -824,6 +855,25 @@ mod tests {
824855
);
825856
}
826857

858+
#[test]
859+
fn test_unreachable_if_defs_respected() {
860+
let contents = r#"
861+
if False:
862+
foo: TypeIs[int]
863+
else:
864+
bar = 1
865+
"#;
866+
let defs = calculate_unranged_definitions_with_unreachable(contents);
867+
let foo = defs.definitions.get(&Name::new("foo")).unwrap();
868+
assert!(matches!(foo.reachability, Reachability::Unreachable));
869+
let bar = defs.definitions.get(&Name::new("bar")).unwrap();
870+
assert!(matches!(bar.reachability, Reachability::Reachable));
871+
872+
let defs_pruned = calculate_unranged_definitions_with_defaults(contents);
873+
assert!(defs_pruned.definitions.get(&Name::new("foo")).is_none());
874+
assert!(defs_pruned.definitions.get(&Name::new("bar")).is_some());
875+
}
876+
827877
#[test]
828878
fn test_definitions() {
829879
let defs = calculate_unranged_definitions_with_defaults(

pyrefly/lib/export/exports.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ impl Exports {
9696
module_info.name(),
9797
module_info.path().is_init(),
9898
sys_info,
99+
false,
99100
);
100101
definitions.inject_implicit_globals();
101102
definitions.ensure_dunder_all(module_info.path().style());

0 commit comments

Comments
 (0)