diff --git a/src/analyzer/expr/call_analyzer.rs b/src/analyzer/expr/call_analyzer.rs index 1b4a77bf..47b2d148 100644 --- a/src/analyzer/expr/call_analyzer.rs +++ b/src/analyzer/expr/call_analyzer.rs @@ -163,6 +163,9 @@ pub(crate) fn reconcile_lower_bounds_with_upper_bounds( let relevant_lower_bounds = get_relevant_bounds(lower_bounds); + // println!("{:#?}", lower_bounds); + // println!("{:#?}", upper_bounds); + let mut union_comparison_result = TypeComparisonResult::new(); let mut has_issue = false; @@ -216,6 +219,7 @@ pub(crate) fn reconcile_lower_bounds_with_upper_bounds( .collect::>(); if equality_strings.len() > 1 { + has_issue = true; analysis_data.maybe_add_issue( Issue::new( IssueKind::IncompatibleTypeParameters, @@ -247,6 +251,7 @@ pub(crate) fn reconcile_lower_bounds_with_upper_bounds( } } + has_issue = true; analysis_data.maybe_add_issue( Issue::new( IssueKind::IncompatibleTypeParameters, @@ -266,6 +271,49 @@ pub(crate) fn reconcile_lower_bounds_with_upper_bounds( } } } + + if !has_issue && upper_bounds.len() > 1 { + let upper_bounds_with_equality = upper_bounds + .iter() + .filter(|bound| bound.equality_bound_classlike.is_some()) + .enumerate() + .collect::>(); + + if upper_bounds_with_equality.is_empty() { + return; + } + + for (i, upper_bound_with_equality) in upper_bounds_with_equality { + for (j, upper_bound) in upper_bounds.iter().enumerate() { + if i == j { + continue; + } + + if !union_type_comparator::can_expression_types_be_identical( + codebase, + &upper_bound_with_equality.bound_type, + &upper_bound.bound_type, + false, + ) { + analysis_data.maybe_add_issue( + Issue::new( + IssueKind::IncompatibleTypeParameters, + format!( + "Incompatible types found for {} ({} is not in {})", + "type variable", + upper_bound.bound_type.get_id(Some(interner)), + upper_bound_with_equality.bound_type.get_id(Some(interner)), + ), + pos, + &None, + ), + statements_analyzer.get_config(), + statements_analyzer.get_file_path_actual(), + ); + } + } + } + } } pub(crate) fn get_generic_param_for_offset( diff --git a/src/analyzer/stmt/return_analyzer.rs b/src/analyzer/stmt/return_analyzer.rs index 27d7590c..5fe1b659 100644 --- a/src/analyzer/stmt/return_analyzer.rs +++ b/src/analyzer/stmt/return_analyzer.rs @@ -425,6 +425,10 @@ pub(crate) fn analyze( if let Some((_, upper_bounds)) = analysis_data.type_variable_bounds.get_mut(&name) { + if bound.equality_bound_classlike.is_none() { + // bit of a hack but this ensures that we add strict checks + bound.equality_bound_classlike = Some(StrId::EMPTY); + } bound.pos = Some(statements_analyzer.get_hpos(&return_expr.1)); upper_bounds.push(bound); } diff --git a/src/ttype/template/standin_type_replacer.rs b/src/ttype/template/standin_type_replacer.rs index 7f55653e..1c04b79e 100644 --- a/src/ttype/template/standin_type_replacer.rs +++ b/src/ttype/template/standin_type_replacer.rs @@ -1998,7 +1998,7 @@ pub fn get_most_specific_type_from_bounds( pub fn get_relevant_bounds(lower_bounds: &Vec) -> Vec<&TemplateBound> { if lower_bounds.len() == 1 { - return vec![lower_bounds.first().unwrap()]; + return vec![&lower_bounds[0]]; } let mut lower_bounds = lower_bounds.iter().collect::>();