Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@ enum Continuation {
post_if: FlowId,
current: FlowId,
else_block: Option<LuaBlock>,
has_else_clause: bool,
},
/// if statement: finalize after the else block completes
IfFinal { post_if: FlowId, else_label: FlowId },
Expand Down Expand Up @@ -764,7 +763,6 @@ impl<'a, 'b> BindEngine<'a, 'b> {
let then_label = self.binder.create_branch_label();
let clauses = if_stat.get_else_if_clause_list().collect::<Vec<_>>();
let else_clause = if_stat.get_else_clause();
let has_else_clause = else_clause.is_some();
let else_block = else_clause.and_then(|clause| clause.get_block());

self.stack.push(Continuation::IfBranchDone {
Expand All @@ -774,7 +772,6 @@ impl<'a, 'b> BindEngine<'a, 'b> {
post_if: post_if_label,
current,
else_block,
has_else_clause,
});
if let Some(then_block) = if_stat.get_block() {
self.stack
Expand Down Expand Up @@ -1114,7 +1111,6 @@ impl<'a, 'b> BindEngine<'a, 'b> {
post_if,
current,
else_block,
has_else_clause,
} => {
self.binder.add_antecedent(post_if, value);
if idx >= clauses.len() {
Expand All @@ -1128,9 +1124,7 @@ impl<'a, 'b> BindEngine<'a, 'b> {
Step::Task(Task::Block(block, else_label))
}
None => {
if !has_else_clause {
self.binder.add_antecedent(post_if, else_label);
}
self.binder.add_antecedent(post_if, else_label);
Step::Done(finalize_if(self.binder, post_if, else_label))
}
}
Expand All @@ -1146,7 +1140,6 @@ impl<'a, 'b> BindEngine<'a, 'b> {
post_if,
current,
else_block,
has_else_clause,
});
if let Some(block) = clause.get_block() {
self.stack.push(Continuation::ThenBlock { block });
Expand Down
51 changes: 51 additions & 0 deletions crates/emmylua_code_analysis/src/compilation/test/flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3155,6 +3155,57 @@ _2 = a[1]
));
}

#[test]
fn test_issue_1207_lesser_array_length_guards() {
let mut ws = VirtualWorkspace::new();
assert!(ws.has_no_diagnostic(
DiagnosticCode::AssignTypeMismatch,
r#"
local a --- @type string[]
if #a <= 1 then error() end

--- @type string
_ = a[2]

local b --- @type string[]
if #b < 2 then error() end

--- @type string
_ = b[2]
"#
));
}

#[test]
fn test_issue_1207_array_length_bound_does_not_overflow() {
let mut ws = VirtualWorkspace::new();
assert!(ws.has_no_diagnostic(
DiagnosticCode::AssignTypeMismatch,
r#"
local a --- @type string[]
if #a <= 9223372036854775807 then error() end

--- @type string
_ = a[1]
"#
));
}

#[test]
fn test_issue_1207_empty_else_preserves_array_length_guard() {
let mut ws = VirtualWorkspace::new();
assert!(ws.has_no_diagnostic(
DiagnosticCode::AssignTypeMismatch,
r#"
local a --- @type string[]
if not (#a > 1) then error() else end

--- @type string
_ = a[2]
"#
));
}

#[test]
fn test_return_cast_with_fallback() {
let mut ws = VirtualWorkspace::new();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,25 +63,46 @@ pub fn get_type_at_binary_expr(
right_expr,
condition_flow.invert(),
),
BinaryOperator::OpGt => try_get_at_gt_or_ge_expr(
BinaryOperator::OpGt => try_get_at_array_len_expr(
db,
cache,
var_ref_id,
flow_node,
left_expr,
right_expr,
condition_flow,
true,
1,
),
BinaryOperator::OpGe => try_get_at_gt_or_ge_expr(
BinaryOperator::OpGe => try_get_at_array_len_expr(
db,
cache,
var_ref_id,
flow_node,
left_expr,
right_expr,
condition_flow,
false,
0,
),
// The false branches are equivalent to `>=` and `>` respectively.
BinaryOperator::OpLt => try_get_at_array_len_expr(
db,
cache,
var_ref_id,
flow_node,
left_expr,
right_expr,
condition_flow.invert(),
0,
),
BinaryOperator::OpLe => try_get_at_array_len_expr(
db,
cache,
var_ref_id,
flow_node,
left_expr,
right_expr,
condition_flow.invert(),
1,
),
BinaryOperator::OpNilCoalescing => {
try_get_at_nil_coalescing(db, cache, var_ref_id, left_expr, condition_flow)
Expand Down Expand Up @@ -177,15 +198,15 @@ fn try_get_at_eq_or_neq_expr(
}

#[allow(clippy::too_many_arguments)]
fn try_get_at_gt_or_ge_expr(
fn try_get_at_array_len_expr(
db: &DbIndex,
cache: &mut LuaInferCache,
var_ref_id: &VarRefId,
flow_node: &FlowNode,
left_expr: LuaExpr,
right_expr: LuaExpr,
condition_flow: InferConditionFlow,
gt: bool,
max_adjustment: i64,
) -> Result<ConditionFlowAction, InferFailReason> {
match left_expr {
LuaExpr::UnaryExpr(unary_expr) => {
Expand Down Expand Up @@ -217,7 +238,7 @@ fn try_get_at_gt_or_ge_expr(
expr: right_expr,
resume: ExprTypeContinuation::ArrayLen {
subquery_condition_flow: condition_flow,
max_adjustment: if gt { 1 } else { 0 },
max_adjustment,
},
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,10 +293,10 @@ impl PendingConditionNarrow {
LuaType::Array(array_type),
LuaType::IntegerConst(i) | LuaType::DocIntegerConst(i),
) if matches!(condition_flow, InferConditionFlow::TrueCondition) => {
let new_array_type = LuaArrayType::new(
array_type.get_base().clone(),
LuaArrayLen::Max(*i + *max_adjustment),
);
// Array bounds are i64, so clamp an exclusive bound above i64::MAX.
let max_len = i.saturating_add(*max_adjustment);
let new_array_type =
LuaArrayType::new(array_type.get_base().clone(), LuaArrayLen::Max(max_len));
LuaType::Array(new_array_type.into())
}
_ => antecedent_type,
Expand Down
Loading