From 3820d2af14eecaf84cb0eb75c4a63397d0ae6337 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Wed, 13 Mar 2024 10:03:08 +0100 Subject: [PATCH] Remove potentially problematic use of ".." in pattern-match Discard pattern are _dangerous_ is used recklessly. The problem comes from maintenance and when adding new fields. We usually don't get any compiler warnings which may lead to missing spots and confusing behaviors. So I have, in some cases, inline discard to explicitly list all fields. That's a bit more cumbersome to write but hopefully will catch a few things for us in the future. --- crates/aiken-lang/src/tipo.rs | 43 +++++---- crates/aiken-lang/src/tipo/environment.rs | 103 ++++++++++++++++------ crates/aiken-lang/src/tipo/expr.rs | 91 +++++++++++-------- crates/aiken-lang/src/tipo/infer.rs | 69 +++++++++++---- 4 files changed, 208 insertions(+), 98 deletions(-) diff --git a/crates/aiken-lang/src/tipo.rs b/crates/aiken-lang/src/tipo.rs index 9a113632..d60cb53b 100644 --- a/crates/aiken-lang/src/tipo.rs +++ b/crates/aiken-lang/src/tipo.rs @@ -81,19 +81,22 @@ impl PartialEq for Type { module, name, args, - .. + opaque, + alias: _, } => { if let Type::App { public: public2, module: module2, name: name2, args: args2, - .. + opaque: opaque2, + alias: _, } = other { name == name2 && module == module2 && public == public2 + && opaque == opaque2 && args.iter().zip(args2).all(|(left, right)| left == right) } else { false @@ -104,7 +107,7 @@ impl PartialEq for Type { if let Type::Fn { args: args2, ret: ret2, - .. + alias: _, } = other { ret == ret2 && args.iter().zip(args2).all(|(left, right)| left == right) @@ -113,7 +116,7 @@ impl PartialEq for Type { } } - Type::Tuple { elems, .. } => { + Type::Tuple { elems, alias: _ } => { if let Type::Tuple { elems: elems2, .. } = other { elems.iter().zip(elems2).all(|(left, right)| left == right) } else { @@ -121,8 +124,12 @@ impl PartialEq for Type { } } - Type::Var { tipo, .. } => { - if let Type::Var { tipo: tipo2, .. } = other { + Type::Var { tipo, alias: _ } => { + if let Type::Var { + tipo: tipo2, + alias: _, + } = other + { tipo == tipo2 } else { false @@ -157,7 +164,7 @@ impl Type { module, name, args, - .. + alias: _, } => Type::App { public, opaque, @@ -166,9 +173,13 @@ impl Type { args, alias, }, - Type::Fn { args, ret, .. } => Type::Fn { args, ret, alias }, - Type::Var { tipo, .. } => Type::Var { tipo, alias }, - Type::Tuple { elems, .. } => Type::Tuple { elems, alias }, + Type::Fn { + args, + ret, + alias: _, + } => Type::Fn { args, ret, alias }, + Type::Var { tipo, alias: _ } => Type::Var { tipo, alias }, + Type::Tuple { elems, alias: _ } => Type::Tuple { elems, alias }, }) } @@ -959,11 +970,13 @@ impl TypeVar { Self::Link { tipo } => tipo.get_inner_types(), Self::Unbound { .. } => vec![], var => { - vec![Type::Var { - tipo: RefCell::new(var.clone()).into(), - alias: None, - } - .into()] + vec![ + Type::Var { + tipo: RefCell::new(var.clone()).into(), + alias: None, + } + .into(), + ] } } } diff --git a/crates/aiken-lang/src/tipo/environment.rs b/crates/aiken-lang/src/tipo/environment.rs index b83482a6..99fd073c 100644 --- a/crates/aiken-lang/src/tipo/environment.rs +++ b/crates/aiken-lang/src/tipo/environment.rs @@ -145,7 +145,12 @@ impl<'a> Environment<'a> { } } - if let Type::Fn { args, ret, .. } = tipo.deref() { + if let Type::Fn { + args, + ret, + alias: _, + } = tipo.deref() + { return if args.len() != arity { Err(Error::IncorrectFunctionCallArity { expected: args.len(), @@ -730,7 +735,7 @@ impl<'a> Environment<'a> { as_name, unqualified, location, - .. + package: _, }) => { let name = module.join("/"); @@ -765,7 +770,6 @@ impl<'a> Environment<'a> { name, location, as_name, - .. } in unqualified { let mut type_imported = false; @@ -990,7 +994,8 @@ impl<'a> Environment<'a> { parameters, location, constructors, - .. + doc: _, + typed_parameters: _, }) => { assert_unique_type_name(names, name, location)?; @@ -1037,7 +1042,8 @@ impl<'a> Environment<'a> { parameters: args, alias: name, annotation: resolved_type, - .. + doc: _, + tipo: _, }) => { assert_unique_type_name(names, name, location)?; @@ -1178,7 +1184,9 @@ impl<'a> Environment<'a> { fun, other_fun, params, - .. + doc: _, + location: _, + end_position: _, }) if kind.is_validator() => { let default_annotation = |mut arg: UntypedArg| { if arg.annotation.is_none() { @@ -1256,7 +1264,10 @@ impl<'a> Environment<'a> { opaque, name, constructors, - .. + doc: _, + location: _, + parameters: _, + typed_parameters: _, }) => { let mut hydrator = hydrators .remove(name) @@ -1299,7 +1310,8 @@ impl<'a> Environment<'a> { label, annotation, location, - .. + tipo: _, + doc: _, }, ) in constructor.arguments.iter().enumerate() { @@ -1389,13 +1401,18 @@ impl<'a> Environment<'a> { } // Collapse right hand side type links. Left hand side will be collapsed in the next block. - if let Type::Var { tipo, .. } = t2.deref() { - if let TypeVar::Link { tipo, .. } = tipo.borrow().deref() { - return self.unify(t1, tipo.clone(), location, allow_cast); + if let Type::Var { tipo, alias } = t2.deref() { + if let TypeVar::Link { tipo } = tipo.borrow().deref() { + return self.unify( + t1, + Type::with_alias(tipo.clone(), alias.clone()), + location, + allow_cast, + ); } } - if let Type::Var { tipo, .. } = t1.deref() { + if let Type::Var { tipo, alias } = t1.deref() { enum Action { Unify(Rc), CouldNotUnify, @@ -1403,7 +1420,9 @@ impl<'a> Environment<'a> { } let action = match tipo.borrow().deref() { - TypeVar::Link { tipo } => Action::Unify(tipo.clone()), + TypeVar::Link { tipo } => { + Action::Unify(Type::with_alias(tipo.clone(), alias.clone())) + } TypeVar::Unbound { id } => { unify_unbound_type(t2.clone(), *id, location)?; @@ -1411,7 +1430,7 @@ impl<'a> Environment<'a> { } TypeVar::Generic { id } => { - if let Type::Var { tipo, .. } = t2.deref() { + if let Type::Var { tipo, alias: _ } = t2.deref() { if tipo.borrow().is_unbound() { *tipo.borrow_mut() = TypeVar::Generic { id: *id }; return Ok(()); @@ -1451,13 +1470,17 @@ impl<'a> Environment<'a> { module: m1, name: n1, args: args1, - .. + public: _, + opaque: _, + alias: _, }, Type::App { module: m2, name: n2, args: args2, - .. + public: _, + opaque: _, + alias: _, }, ) if m1 == m2 && n1 == n2 && args1.len() == args2.len() => { for (a, b) in args1.iter().zip(args2) { @@ -1470,9 +1493,16 @@ impl<'a> Environment<'a> { Ok(()) } - (Type::Tuple { elems: elems1, .. }, Type::Tuple { elems: elems2, .. }) - if elems1.len() == elems2.len() => - { + ( + Type::Tuple { + elems: elems1, + alias: _, + }, + Type::Tuple { + elems: elems2, + alias: _, + }, + ) if elems1.len() == elems2.len() => { for (a, b) in elems1.iter().zip(elems2) { unify_enclosed_type( t1.clone(), @@ -1487,12 +1517,12 @@ impl<'a> Environment<'a> { Type::Fn { args: args1, ret: retrn1, - .. + alias: _, }, Type::Fn { args: args2, ret: retrn2, - .. + alias: _, }, ) if args1.len() == args2.len() => { for (a, b) in args1.iter().zip(args2) { @@ -1678,10 +1708,14 @@ pub enum EntityKind { /// could cause naively-implemented type checking to diverge. /// While traversing the type tree. fn unify_unbound_type(tipo: Rc, own_id: u64, location: Span) -> Result<(), Error> { - if let Type::Var { tipo, .. } = tipo.deref() { + if let Type::Var { tipo, alias } = tipo.deref() { let new_value = match tipo.borrow().deref() { - TypeVar::Link { tipo, .. } => { - return unify_unbound_type(tipo.clone(), own_id, location); + TypeVar::Link { tipo } => { + return unify_unbound_type( + Type::with_alias(tipo.clone(), alias.clone()), + own_id, + location, + ); } TypeVar::Unbound { id } => { @@ -1702,7 +1736,14 @@ fn unify_unbound_type(tipo: Rc, own_id: u64, location: Span) -> Result<(), } match tipo.deref() { - Type::App { args, .. } => { + Type::App { + args, + module: _, + name: _, + public: _, + alias: _, + opaque: _, + } => { for arg in args { unify_unbound_type(arg.clone(), own_id, location)? } @@ -1710,7 +1751,11 @@ fn unify_unbound_type(tipo: Rc, own_id: u64, location: Span) -> Result<(), Ok(()) } - Type::Fn { args, ret, .. } => { + Type::Fn { + args, + ret, + alias: _, + } => { for arg in args { unify_unbound_type(arg.clone(), own_id, location)?; } @@ -1718,7 +1763,7 @@ fn unify_unbound_type(tipo: Rc, own_id: u64, location: Span) -> Result<(), unify_unbound_type(ret.clone(), own_id, location) } - Type::Tuple { elems, .. } => { + Type::Tuple { elems, alias: _ } => { for elem in elems { unify_unbound_type(elem.clone(), own_id, location)? } @@ -1805,9 +1850,9 @@ pub(super) fn assert_no_labeled_arguments(args: &[CallArg]) -> Option<(Spa } pub(super) fn collapse_links(t: Rc) -> Rc { - if let Type::Var { tipo, .. } = t.deref() { + if let Type::Var { tipo, alias } = t.deref() { if let TypeVar::Link { tipo } = tipo.borrow().deref() { - return tipo.clone(); + return Type::with_alias(tipo.clone(), alias.clone()); } } t diff --git a/crates/aiken-lang/src/tipo/expr.rs b/crates/aiken-lang/src/tipo/expr.rs index 9a7e1abd..5777fe4d 100644 --- a/crates/aiken-lang/src/tipo/expr.rs +++ b/crates/aiken-lang/src/tipo/expr.rs @@ -211,10 +211,12 @@ impl<'a, 'b> ExprTyper<'a, 'b> { match expr { UntypedExpr::ErrorTerm { location } => Ok(self.infer_error_term(location)), - UntypedExpr::Var { location, name, .. } => self.infer_var(name, location), + UntypedExpr::Var { location, name } => self.infer_var(name, location), UntypedExpr::UInt { - location, value, .. + location, + value, + base: _, } => Ok(self.infer_uint(value, location)), UntypedExpr::Sequence { @@ -222,13 +224,9 @@ impl<'a, 'b> ExprTyper<'a, 'b> { location, } => self.infer_seq(location, expressions), - UntypedExpr::Tuple { - location, elems, .. - } => self.infer_tuple(elems, location), + UntypedExpr::Tuple { location, elems } => self.infer_tuple(elems, location), - UntypedExpr::String { - location, value, .. - } => Ok(self.infer_string(value, location)), + UntypedExpr::String { location, value } => Ok(self.infer_string(value, location)), UntypedExpr::LogicalOpChain { kind, @@ -244,7 +242,6 @@ impl<'a, 'b> ExprTyper<'a, 'b> { arguments: args, body, return_annotation, - .. } => self.infer_fn( args, &[], @@ -265,7 +262,6 @@ impl<'a, 'b> ExprTyper<'a, 'b> { patterns, value, kind, - .. } => { // at this point due to backpassing rewrites, // patterns is guaranteed to have one item @@ -295,14 +291,12 @@ impl<'a, 'b> ExprTyper<'a, 'b> { location, elements, tail, - .. } => self.infer_list(elements, tail, location), UntypedExpr::Call { location, fun, arguments: args, - .. } => self.infer_call(*fun, args, location), UntypedExpr::BinOp { @@ -310,21 +304,18 @@ impl<'a, 'b> ExprTyper<'a, 'b> { name, left, right, - .. } => self.infer_binop(name, *left, *right, location), UntypedExpr::FieldAccess { location, label, container, - .. } => self.infer_field_access(*container, label, location), UntypedExpr::TupleIndex { location, index, tuple, - .. } => self.infer_tuple_index(*tuple, index, location), UntypedExpr::ByteArray { @@ -334,7 +325,9 @@ impl<'a, 'b> ExprTyper<'a, 'b> { } => self.infer_bytearray(bytes, preferred_format, location), UntypedExpr::CurvePoint { - location, point, .. + location, + point, + preferred_format: _, } => self.infer_curve_point(*point, location), UntypedExpr::RecordUpdate { @@ -578,7 +571,10 @@ impl<'a, 'b> ExprTyper<'a, 'b> { ValueConstructorVariant::Record { field_map: Some(field_map), constructors_count, - .. + name: _, + arity: _, + location: _, + module: _, } => (field_map, *constructors_count), _ => { return Err(Error::RecordUpdateInvalidConstructor { @@ -704,7 +700,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> { Ok(record_access) => Ok(record_access), Err(err) => match container { - UntypedExpr::Var { name, location, .. } => { + UntypedExpr::Var { name, location } => { let module_access = self.infer_module_access(&name, label, &location, access_location); @@ -894,7 +890,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> { annotation, location, doc, - .. + tipo: _, } = arg; let tipo = annotation @@ -1087,7 +1083,8 @@ impl<'a, 'b> ExprTyper<'a, 'b> { ( Type::Fn { args: expected_arguments, - .. + ret: _, + alias: _, }, UntypedExpr::Fn { arguments, @@ -1095,7 +1092,6 @@ impl<'a, 'b> ExprTyper<'a, 'b> { return_annotation, location, fn_style, - .. }, ) if fn_style != FnStyle::Capture && expected_arguments.len() == arguments.len() => { self.infer_fn( @@ -1398,9 +1394,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> { base, }), - Constant::String { - location, value, .. - } => Ok(Constant::String { location, value }), + Constant::String { location, value } => Ok(Constant::String { location, value }), Constant::ByteArray { location, @@ -1748,7 +1742,6 @@ impl<'a, 'b> ExprTyper<'a, 'b> { value, kind, patterns, - .. } = breakpoint else { unreachable!("backpass misuse: breakpoint isn't an Assignment ?!"); @@ -1776,7 +1769,9 @@ impl<'a, 'b> ExprTyper<'a, 'b> { // in front of the continuation sequence. This is because we do not support patterns in function argument // (which is perhaps something we should support?). match pattern { - Pattern::Var { name, .. } | Pattern::Discard { name, .. } if kind.is_let() => { + Pattern::Var { name, location: _ } | Pattern::Discard { name, location: _ } + if kind.is_let() => + { names.push((name.clone(), annotation)); } _ => { @@ -1806,7 +1801,11 @@ impl<'a, 'b> ExprTyper<'a, 'b> { } match *value { - UntypedExpr::Call { fun, arguments, .. } => { + UntypedExpr::Call { + fun, + arguments, + location: _, + } => { let mut new_arguments = Vec::new(); new_arguments.extend(arguments); new_arguments.push(CallArg { @@ -1832,7 +1831,8 @@ impl<'a, 'b> ExprTyper<'a, 'b> { fn_style, ref arguments, ref return_annotation, - .. + location: _, + body: _, } => { let return_annotation = return_annotation.clone(); @@ -1891,7 +1891,10 @@ impl<'a, 'b> ExprTyper<'a, 'b> { breakpoint = Some(expression); } UntypedExpr::Assignment { - patterns, location, .. + patterns, + location, + value: _, + kind: _, } if patterns.len() > 1 => { return Err(Error::UnexpectedMultiPatternAssignment { arrow: patterns @@ -2012,7 +2015,10 @@ impl<'a, 'b> ExprTyper<'a, 'b> { let tuple = self.infer(tuple)?; let tipo = match *tuple.tipo() { - Type::Tuple { ref elems, .. } => { + Type::Tuple { + ref elems, + alias: _, + } => { let size = elems.len(); if index >= size { Err(Error::TupleIndexOutOfBound { @@ -2341,7 +2347,14 @@ fn assert_assignment(expr: TypedExpr) -> Result { pub fn ensure_serialisable(allow_fn: bool, t: Rc, location: Span) -> Result<(), Error> { match t.deref() { - Type::App { args, .. } => { + Type::App { + args, + name: _, + module: _, + public: _, + opaque: _, + alias: _, + } => { if t.is_ml_result() { return Err(Error::IllegalTypeInData { tipo: t.clone(), @@ -2356,7 +2369,7 @@ pub fn ensure_serialisable(allow_fn: bool, t: Rc, location: Span) -> Resul Ok(()) } - Type::Tuple { elems, .. } => { + Type::Tuple { elems, alias: _ } => { elems .iter() .map(|e| ensure_serialisable(false, e.clone(), location)) @@ -2365,7 +2378,11 @@ pub fn ensure_serialisable(allow_fn: bool, t: Rc, location: Span) -> Resul Ok(()) } - Type::Fn { args, ret, .. } => { + Type::Fn { + args, + ret, + alias: _, + } => { if !allow_fn { return Err(Error::IllegalTypeInData { tipo: t.clone(), @@ -2380,10 +2397,14 @@ pub fn ensure_serialisable(allow_fn: bool, t: Rc, location: Span) -> Resul ensure_serialisable(allow_fn, ret.clone(), location) } - Type::Var { tipo, .. } => match tipo.borrow().deref() { + Type::Var { tipo, alias } => match tipo.borrow().deref() { TypeVar::Unbound { .. } => Ok(()), TypeVar::Generic { .. } => Ok(()), - TypeVar::Link { tipo } => ensure_serialisable(allow_fn, tipo.clone(), location), + TypeVar::Link { tipo } => ensure_serialisable( + allow_fn, + Type::with_alias(tipo.clone(), alias.clone()), + location, + ), }, } } diff --git a/crates/aiken-lang/src/tipo/infer.rs b/crates/aiken-lang/src/tipo/infer.rs index 08f17972..e40c92f6 100644 --- a/crates/aiken-lang/src/tipo/infer.rs +++ b/crates/aiken-lang/src/tipo/infer.rs @@ -197,7 +197,8 @@ fn infer_definition( ArgName::Named { name, is_validator_param, - .. + label: _, + location: _, } if *is_validator_param => { environment.insert_variable( name.to_string(), @@ -383,7 +384,9 @@ fn infer_definition( .get_mut(&f.name) .expect("Could not find preregistered type for test"); if let Type::Fn { - ref ret, ref alias, .. + ref ret, + ref alias, + args: _, } = scope.tipo.as_ref() { scope.tipo = Rc::new(Type::Fn { @@ -425,7 +428,11 @@ fn infer_definition( arguments: match typed_via { Some((via, tipo)) => { let Arg { - arg_name, location, .. + arg_name, + location, + annotation: _, + doc: _, + tipo: _, } = typed_f .arguments .first() @@ -457,7 +464,7 @@ fn infer_definition( alias, parameters, annotation, - .. + tipo: _, }) => { let tipo = environment .get_type_constructor(&None, &alias, location) @@ -484,7 +491,7 @@ fn infer_definition( name, parameters, constructors: untyped_constructors, - .. + typed_parameters: _, }) => { let constructors = untyped_constructors .into_iter() @@ -514,7 +521,7 @@ fn infer_definition( annotation, location, doc, - .. + tipo: _, }, t, )| { @@ -561,7 +568,14 @@ fn infer_definition( }; for constr in &typed_data.constructors { - for RecordConstructorArg { tipo, location, .. } in &constr.arguments { + for RecordConstructorArg { + tipo, + location, + doc: _, + label: _, + annotation: _, + } in &constr.arguments + { if tipo.is_function() { return Err(Error::FunctionTypeInData { location: *location, @@ -585,7 +599,7 @@ fn infer_definition( module, as_name, unqualified, - .. + package: _, }) => { let name = module.join("/"); @@ -616,7 +630,7 @@ fn infer_definition( annotation, public, value, - .. + tipo: _, }) => { let typed_expr = ExprTyper::new(environment, lines, tracing).infer_const(&annotation, *value)?; @@ -672,7 +686,7 @@ fn infer_function( return_annotation, end_position, can_error, - .. + return_type: _, } = f; let preregistered_fn = environment @@ -773,9 +787,18 @@ fn infer_fuzzer( }; match tipo.borrow() { - Type::Fn { ret, .. } => match ret.borrow() { + Type::Fn { + ret, + args: _, + alias: _, + } => match ret.borrow() { Type::App { - module, name, args, .. + module, + name, + args, + public: _, + opaque: _, + alias: _, } if module.is_empty() && name == "Option" && args.len() == 1 => { match args.first().expect("args.len() == 1").borrow() { Type::Tuple { elems, .. } if elems.len() == 2 => { @@ -805,10 +828,13 @@ fn infer_fuzzer( _ => Err(could_not_unify()), }, - Type::Var { tipo, .. } => match &*tipo.deref().borrow() { - TypeVar::Link { tipo } => { - infer_fuzzer(environment, expected_inner_type, tipo, location) - } + Type::Var { tipo, alias } => match &*tipo.deref().borrow() { + TypeVar::Link { tipo } => infer_fuzzer( + environment, + expected_inner_type, + &Type::with_alias(tipo.clone(), alias.clone()), + location, + ), _ => Err(Error::GenericLeftAtBoundary { location: *location, }), @@ -821,7 +847,12 @@ fn infer_fuzzer( fn annotate_fuzzer(tipo: &Type, location: &Span) -> Result { match tipo { Type::App { - name, module, args, .. + name, + module, + args, + public: _, + opaque: _, + alias: _, } => { let arguments = args .iter() @@ -839,7 +870,7 @@ fn annotate_fuzzer(tipo: &Type, location: &Span) -> Result { }) } - Type::Tuple { elems, .. } => { + Type::Tuple { elems, alias: _ } => { let elems = elems .iter() .map(|arg| annotate_fuzzer(arg, location)) @@ -850,7 +881,7 @@ fn annotate_fuzzer(tipo: &Type, location: &Span) -> Result { }) } - Type::Var { tipo, .. } => match &*tipo.deref().borrow() { + Type::Var { tipo, alias: _ } => match &*tipo.deref().borrow() { TypeVar::Link { tipo } => annotate_fuzzer(tipo, location), _ => Err(Error::GenericLeftAtBoundary { location: *location,