Skip to content
Open
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
31 changes: 31 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,36 @@ tempfile = { version = "3.27.0", optional = true }
tokio = { version = "1.50.0", features = ["full"], optional = true }
tower-lsp = { version = "0.20.0", optional = true }

[lints.clippy]
# ── Deny: these break CI immediately ──
collapsible_if = "deny"
collapsible_else_if = "deny"
needless_bool = "deny"
needless_return = "deny"
redundant_else = "deny"
manual_let_else = "deny"
unnested_or_patterns = "deny"
single_match_else = "deny"
fn_params_excessive_bools = "deny"
struct_excessive_bools = "deny"

# ── Complexity ──
cognitive_complexity = "deny"
too_many_lines = "deny"
match_same_arms = "deny"

# ── Code quality (pedantic) ──
redundant_closure = "deny"
needless_pass_by_value = "deny"
wildcard_imports = "deny"
manual_string_new = "deny"
uninlined_format_args = "deny"
needless_continue = "deny"
cast_lossless = "deny"
explicit_iter_loop = "deny"
unused_self = "deny"
unnecessary_wraps = "deny"
match_wildcard_for_single_variants = "deny"

[dev-dependencies]
insta = "1.47.2"
9 changes: 3 additions & 6 deletions src/checker/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,7 @@ impl Checker {
let inner_ty = self.check_expr(inner);
Type::Settable(Box::new(inner_ty))
}
ExprKind::Clear => Type::Settable(Box::new(Type::Unknown)),
ExprKind::Unchanged => Type::Settable(Box::new(Type::Unknown)),
ExprKind::Clear | ExprKind::Unchanged => Type::Settable(Box::new(Type::Unknown)),
ExprKind::Todo => {
self.emit_warning_with_help(
"`todo` is a placeholder that will panic at runtime",
Expand Down Expand Up @@ -168,13 +167,12 @@ impl Checker {
}
last_type
}),
ExprKind::Grouped(inner) => self.check_expr(inner),
ExprKind::Grouped(inner) | ExprKind::Spread(inner) => self.check_expr(inner),
ExprKind::Array(elements) => self.check_array(elements),
ExprKind::Tuple(elements) => {
let types: Vec<Type> = elements.iter().map(|el| self.check_expr(el)).collect();
Type::Tuple(types)
}
ExprKind::Spread(inner) => self.check_expr(inner),
ExprKind::Object(fields) => {
let field_types: Vec<(String, Type)> = fields
.iter()
Expand Down Expand Up @@ -418,8 +416,7 @@ impl Checker {
Type::Unknown
}
}
Type::Unknown | Type::Foreign(_) | Type::Never => Type::Unknown,
Type::Var(_) => Type::Unknown,
Type::Unknown | Type::Foreign(_) | Type::Never | Type::Var(_) => Type::Unknown,
_ => {
if let Type::Named(name) = &obj_ty
&& self.env.lookup_type(name).is_none()
Expand Down
3 changes: 1 addition & 2 deletions src/checker/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,7 @@ impl Checker {
fn tuple_element_type(final_type: &Type, i: usize) -> Type {
match final_type {
Type::Tuple(types) => types.get(i).cloned().unwrap_or(Type::Unknown),
Type::Unknown | Type::Var(_) => Type::Unknown,
_ => Type::Unknown,
Type::Unknown | Type::Var(_) | _ => Type::Unknown,
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/checker/match_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ impl Checker {
// Resolve Named types to their actual definitions.
let resolved_ty;
let subject_ty = match subject_ty {
Type::Foreign(_) | Type::Promise(_) => subject_ty,
Type::Named(type_name) => {
if let Some(actual) = self.env.lookup(type_name) {
resolved_ty = actual.clone();
Expand All @@ -67,7 +66,7 @@ impl Checker {
subject_ty
}
}
_ => subject_ty,
Type::Foreign(_) | Type::Promise(_) | _ => subject_ty,
};

let has_catch_all = arms.iter().any(|arm| {
Expand Down
23 changes: 11 additions & 12 deletions src/checker/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,17 @@ impl Checker {
functions: &[FunctionDecl],
span: Span,
) {
let trait_methods = match self.traits.trait_defs.get(trait_name) {
Some(methods) => methods.clone(),
None => {
self.emit_error_with_help(
format!("unknown trait `{trait_name}`"),
span,
ErrorCode::UnknownTrait,
"not defined",
"check the spelling or define this trait",
);
return;
}
let trait_methods = if let Some(methods) = self.traits.trait_defs.get(trait_name) {
methods.clone()
} else {
self.emit_error_with_help(
format!("unknown trait `{trait_name}`"),
span,
ErrorCode::UnknownTrait,
"not defined",
"check the spelling or define this trait",
);
return;
};

// Check that all required methods are implemented
Expand Down
9 changes: 5 additions & 4 deletions src/checker/type_compat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ impl Checker {
_ => true,
}
}
(Type::Promise(a), Type::Promise(b)) => self.types_unifiable(a, b),
(Type::Array(a), Type::Array(b)) => self.types_unifiable(a, b),
(Type::Promise(a), Type::Promise(b)) | (Type::Array(a), Type::Array(b)) => {
self.types_unifiable(a, b)
}
(Type::Tuple(a), Type::Tuple(b)) => {
a.len() == b.len()
&& a.iter()
Expand Down Expand Up @@ -209,8 +210,8 @@ impl Checker {
| (Type::Unit, Type::Unit)
| (Type::Undefined, Type::Undefined) => true,
(Type::String, Type::StringLiteral(_)) => true,
(Type::StringLiteral(a), Type::StringLiteral(b)) => a == b,
(Type::Named(a), Type::Named(b)) => a == b,
(Type::StringLiteral(a), Type::StringLiteral(b))
| (Type::Named(a), Type::Named(b)) => a == b,
(Type::Named(a), Type::Union { name: b, .. })
| (Type::Union { name: a, .. }, Type::Named(b)) => a == b,
(expected, actual) if expected.is_result() && actual.is_result() => {
Expand Down
5 changes: 1 addition & 4 deletions src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -646,10 +646,7 @@ fn collect_value_names_from_expr(expr: &Expr, names: &mut HashSet<String>) {
collect_value_names_from_expr(right, names);
}
ExprKind::Unary { operand, .. } => collect_value_names_from_expr(operand, names),
ExprKind::Unwrap(e) => {
collect_value_names_from_expr(e, names);
}
ExprKind::Value(e) => {
ExprKind::Unwrap(e) | ExprKind::Value(e) => {
collect_value_names_from_expr(e, names);
}
ExprKind::Match { subject, arms } => {
Expand Down
110 changes: 50 additions & 60 deletions src/codegen/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,8 @@ impl Codegen {
}

// Unchanged → should only appear inside Construct args (filtered out)
ExprKind::Unchanged => {
// Unit → undefined
ExprKind::Unchanged | ExprKind::Unit => {
self.push("undefined");
}

Expand All @@ -345,10 +346,6 @@ impl Codegen {
self.push(THROW_UNREACHABLE);
}

ExprKind::Unit => {
self.push("undefined");
}

ExprKind::Jsx(element) => {
self.has_jsx = true;
self.emit_jsx(element);
Expand Down Expand Up @@ -410,8 +407,8 @@ impl Codegen {
}

ExprKind::DotShorthand { field, predicate } => {
match predicate {
Some((op, rhs)) => match op {
if let Some((op, rhs)) = predicate {
match op {
BinOp::Eq => {
self.needs_deep_equal = true;
self.push(&format!("(_x) => {DEEP_EQUAL_FN}(_x."));
Expand All @@ -434,12 +431,11 @@ impl Codegen {
self.push(&format!(" {} ", binop_str(*op)));
self.emit_expr(rhs);
}
},
None => {
// `.field` → `(_x) => _x.field`
self.push("(_x) => _x.");
self.push(field);
}
} else {
// `.field` → `(_x) => _x.field`
self.push("(_x) => _x.");
self.push(field);
}
}
}
Expand Down Expand Up @@ -576,62 +572,56 @@ impl Codegen {

/// Like emit_block_expr but adds implicit return to the last expression.
pub(super) fn emit_block_expr_with_return(&mut self, expr: &Expr) {
match &expr.kind {
ExprKind::Block(items) => {
self.push("{");
self.newline();
self.indent += 1;
for (i, item) in items.iter().enumerate() {
let is_last = i == items.len() - 1;
if is_last && matches!(item.kind, ItemKind::Expr(_)) {
self.emit_indent();
self.push("return ");
if let ItemKind::Expr(e) = &item.kind {
self.emit_expr(e);
}
self.push(";");
} else {
self.emit_item(item);
if let ExprKind::Block(items) = &expr.kind {
self.push("{");
self.newline();
self.indent += 1;
for (i, item) in items.iter().enumerate() {
let is_last = i == items.len() - 1;
if is_last && matches!(item.kind, ItemKind::Expr(_)) {
self.emit_indent();
self.push("return ");
if let ItemKind::Expr(e) = &item.kind {
self.emit_expr(e);
}
self.newline();
self.push(";");
} else {
self.emit_item(item);
}
self.indent -= 1;
self.emit_indent();
self.push("}");
}
_ => {
self.push("{");
self.newline();
self.indent += 1;
self.emit_indent();
self.push("return ");
self.emit_expr(expr);
self.push(";");
self.newline();
self.indent -= 1;
self.emit_indent();
self.push("}");
}
self.indent -= 1;
self.emit_indent();
self.push("}");
} else {
self.push("{");
self.newline();
self.indent += 1;
self.emit_indent();
self.push("return ");
self.emit_expr(expr);
self.push(";");
self.newline();
self.indent -= 1;
self.emit_indent();
self.push("}");
}
}

pub(super) fn emit_block_expr(&mut self, expr: &Expr) {
match &expr.kind {
ExprKind::Block(items) => {
self.emit_block_items(items);
}
_ => {
self.push("{");
self.newline();
self.indent += 1;
self.emit_indent();
self.emit_expr(expr);
self.push(";");
self.newline();
self.indent -= 1;
self.emit_indent();
self.push("}");
}
if let ExprKind::Block(items) = &expr.kind {
self.emit_block_items(items);
} else {
self.push("{");
self.newline();
self.indent += 1;
self.emit_indent();
self.emit_expr(expr);
self.push(";");
self.newline();
self.indent -= 1;
self.emit_indent();
self.push("}");
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/codegen/match_emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,10 +410,10 @@ fn collect_bindings_inner(
bindings.push((name.clone(), rest_access));
}
}
PatternKind::StringPattern { .. } => {
// String pattern bindings are handled directly in emit_match_body
}
PatternKind::Wildcard | PatternKind::Literal(_) | PatternKind::Range { .. } => {}
PatternKind::StringPattern { .. }
| PatternKind::Wildcard
| PatternKind::Literal(_)
| PatternKind::Range { .. } => {}
}
}

Expand Down
8 changes: 3 additions & 5 deletions src/cst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,11 +276,9 @@ impl<'src> CstParser<'src> {
// - EOF
!matches!(
self.current_kind(),
Some(TokenKind::LessThan)
| Some(TokenKind::LeftBrace)
| Some(TokenKind::RightBrace)
| Some(TokenKind::Eof)
| None
Some(
TokenKind::LessThan | TokenKind::LeftBrace | TokenKind::RightBrace | TokenKind::Eof
) | None
)
}

Expand Down
Loading
Loading