diff --git a/.cargo/config.toml b/.cargo/config.toml index 56933fee..f24b4f9b 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -6,23 +6,24 @@ rustflags = [ "-Dunused_crate_dependencies", "-Dclippy::all", "-Dclippy::pedantic", - "-Aclippy::blocks_in_if_conditions", # too many false positives with rustfmt's style - "-Aclippy::empty_enum", # for type-level programming - "-Aclippy::enum_glob_use", # alternative is too verbose - "-Aclippy::if_not_else", # too opinionated, sometimes the negative case is the more common one - "-Aclippy::items_after_statements", # too opinionated - "-Aclippy::match_bool", # too opinionated - "-Aclippy::missing_errors_doc", # not a priority right now - "-Aclippy::missing_panics_doc", # @Temporary, a churn to fix, not a priority right now - "-Aclippy::module_name_repetitions", # false positives, too opinionated - "-Aclippy::must_use_candidate", # @Temporary, a churn to fix, not a priority right now - "-Aclippy::result_unit_err", # ‘Result<_, ()>’ has its uses, in some cases an alt. to ‘Option<_>’ - "-Aclippy::return_self_not_must_use", # @Temporary, a churn to fix, not a priority right now - "-Aclippy::similar_names", # too strict - "-Aclippy::single_match_else", # too opinionated, match exprs look better in many cases - "-Aclippy::struct_excessive_bools", # too many false postives with CLI flag structs - "-Aclippy::too_many_lines", # too opinionated - "-Aclippy::trait_duplication_in_bounds", # @Temporary false positives: rust-clippy#8757 + "-Aclippy::blocks_in_if_conditions", # too many false positives with rustfmt's style + "-Aclippy::empty_enum", # for type-level programming + "-Aclippy::enum_glob_use", # alternative is too verbose + "-Aclippy::if_not_else", # too opinionated, sometimes the negative case is the more common one + "-Aclippy::items_after_statements", # too opinionated + "-Aclippy::match_bool", # too opinionated + "-Aclippy::missing_errors_doc", # not a priority right now + "-Aclippy::missing_panics_doc", # @Temporary, a churn to fix, not a priority right now + "-Aclippy::module_name_repetitions", # false positives, too opinionated + "-Aclippy::must_use_candidate", # @Temporary, a churn to fix, not a priority right now + "-Aclippy::result_unit_err", # ‘Result<_, ()>’ has its uses, in some cases an alt. to ‘Option<_>’ + "-Aclippy::return_self_not_must_use", # @Temporary, a churn to fix, not a priority right now + "-Aclippy::similar_names", # too strict + "-Aclippy::single_match_else", # too opinionated, match exprs look better in many cases + "-Aclippy::struct_excessive_bools", # too many false postives with CLI flag structs + "-Aclippy::too_many_lines", # too opinionated + "-Aclippy::trait_duplication_in_bounds", # @Temporary false positives: rust-clippy#8757 + "-Aclippy::redundant_closure_for_method_calls", # @Temporary false positives: rust-clippy#9335 ] # workaround for cargo#5034 # Used by the GitHub CI workflow. diff --git a/README.adoc b/README.adoc index 758c75b9..866cf8e2 100644 --- a/README.adoc +++ b/README.adoc @@ -55,7 +55,7 @@ data Option A of use Option.(none, some) @public -map 'A 'B (x: Option A) (f: A -> B): B = +map 'A 'B (f: A -> B) (x: Option A): Option B = case x of none => none some (let x) => some (f x) @@ -63,7 +63,7 @@ map 'A 'B (x: Option A) (f: A -> B): B = use extern.core.(type.Type, nat.(Nat, +, *)) process (n: Option Nat): Option Nat = - map n for n => + n 1 + map (for n => + n 1) n @public @transparent diff --git a/compiler/ast/src/format.rs b/compiler/ast/src/format.rs index d7a453fc..1d34e350 100644 --- a/compiler/ast/src/format.rs +++ b/compiler/ast/src/format.rs @@ -75,7 +75,7 @@ mod format_struct { pub(super) fn name(mut self, name: &str) -> Self { self.result = self .result - .and_then(|_| write!(self.formatter, "{}", name.color(palette::NAME).bold())); + .and_then(|()| write!(self.formatter, "{}", name.color(palette::NAME).bold())); self } @@ -86,7 +86,7 @@ mod format_struct { self.indentation = self.indentation.increased(); } - self.result = self.result.and_then(|_| { + self.result = self.result.and_then(|()| { if self.inline { write!(self.formatter, " ") } else { @@ -94,7 +94,7 @@ mod format_struct { } }); - self.result = self.result.and_then(|_| { + self.result = self.result.and_then(|()| { if !self.inline { write!(self.formatter, "{}", self.indentation)?; } @@ -589,8 +589,8 @@ impl Format for super::Field { fn format(&self, f: &mut Formatter<'_>, indentation: Indentation) -> Result { FormatStruct::new(f, indentation) .name("Field") - .field("name", &self.name) - .field("value", &self.item) + .field("binder", &self.binder) + .field("body", &self.body) .finish() } } diff --git a/compiler/ast/src/item.rs b/compiler/ast/src/item.rs index 5de2e862..eca84899 100644 --- a/compiler/ast/src/item.rs +++ b/compiler/ast/src/item.rs @@ -77,6 +77,6 @@ pub struct RecordLiteral { pub struct Field { // @Task generalize this to some new kind of path that is delimited by "::" OR "." - pub name: Identifier, - pub item: Option, + pub binder: Identifier, + pub body: Option, } diff --git a/compiler/codegen_llvm/src/lib.rs b/compiler/codegen_llvm/src/lib.rs index a00d70cc..9eb23b90 100644 --- a/compiler/codegen_llvm/src/lib.rs +++ b/compiler/codegen_llvm/src/lib.rs @@ -1,5 +1,5 @@ //! The LLVM-IR generator. -#![feature(let_chains, io_error_other)] +#![feature(let_chains)] #![allow(clippy::match_same_arms)] // @Temporary use diagnostics::{error::Result, Diagnostic}; @@ -379,6 +379,7 @@ impl<'a, 'ctx> Generator<'a, 'ctx> { PiType(_) => todo!(), Number(number) => self.compile_number(number).into(), Text(_) => todo!(), + Record(_) => todo!(), Binding(_) => todo!(), Lambda(_) | CaseAnalysis(_) @@ -437,6 +438,7 @@ impl<'a, 'ctx> Generator<'a, 'ctx> { } Number(number) => Some(self.compile_number(number).into()), Text(_) => todo!("compiling text"), + Record(_) => todo!("compiling records"), Binding(binding) if self.session.specials().is(binding.0, Type::Type) => None, Binding(binding) => { use hir::Index::*; @@ -531,7 +533,7 @@ impl<'a, 'ctx> Generator<'a, 'ctx> { IntrinsicApplication(_) => todo!(), Projection(_) => todo!(), Error(_) => todo!(), - Number(_) | Text(_) | IO(_) => unreachable!(), + Number(_) | Text(_) | Record(_) | IO(_) => unreachable!(), } } @@ -547,15 +549,14 @@ impl<'a, 'ctx> Generator<'a, 'ctx> { codomain.fn_type(&[domain.into()], false) } Application(_) => todo!(), - Number(_) | Text(_) => unreachable!(), Binding(_) => todo!(), Lambda(_) => todo!(), CaseAnalysis(_) => todo!(), Substituted(_) => todo!(), IntrinsicApplication(_) => todo!(), Projection(_) => todo!(), - IO(_) => todo!(), Error(_) => todo!(), + Number(_) | Text(_) | Record(_) | IO(_) => unreachable!(), } } } @@ -584,6 +585,7 @@ impl ExpressionExt for hir::Expression { Substituted(_) => todo!(), Projection(_) => todo!(), IO(_) => todo!(), + Record(_) => todo!(), Error(_) => todo!(), } } diff --git a/compiler/diagnostics/src/format/test.rs b/compiler/diagnostics/src/format/test.rs index 00267be2..efed8dbb 100644 --- a/compiler/diagnostics/src/format/test.rs +++ b/compiler/diagnostics/src/format/test.rs @@ -474,7 +474,7 @@ warning: it hopefully help: less helpful tip", - ) + ); } #[test] @@ -768,7 +768,7 @@ warning: this file looks spooky ┌─ scary.exe │ help: better delete it", - ) + ); } #[test] diff --git a/compiler/documenter/src/format.rs b/compiler/documenter/src/format.rs index 4b13c23a..af3adbfd 100644 --- a/compiler/documenter/src/format.rs +++ b/compiler/documenter/src/format.rs @@ -198,8 +198,9 @@ impl<'a> Formatter<'a> { Number(literal) => self.write(&literal.to_string()), Text(literal) => self.write(&literal.to_string()), Binding(binding) => self.format_binder(&binding.0), - // @Beacon @Temporary @Task just write out the path + // @Task Projection(_projection) => self.write("⟨projection⟩"), + Record(_record) => self.write("⟨record⟩"), IO(io) => { self.write("⟨io "); self.write(&io.index.to_string()); diff --git a/compiler/documenter/src/lib.rs b/compiler/documenter/src/lib.rs index b51a43db..d7ee9b51 100644 --- a/compiler/documenter/src/lib.rs +++ b/compiler/documenter/src/lib.rs @@ -850,10 +850,10 @@ fn add_declaration_attribute(attribute: &Attribute, parent: &mut Element<'_>, ur Unstable(_) => parent.add_child(Element::div("experimental").child("experimental")), Unsafe => parent.add_child(Element::div("unsafe").child("unsafe")), - // rendered separately + // Rendered separately. Doc { .. } => {} - // not rendered + // Not rendered since they are not part of the API. Allow { .. } | Deny { .. } | Forbid { .. } @@ -863,10 +863,11 @@ fn add_declaration_attribute(attribute: &Attribute, parent: &mut Element<'_>, ur | Statistics | Warn { .. } => {} - // should not exist at this point in time + // Not rendered since they are truly internal and not part of the surface language. + Context | Record | Trait => {} + + // Should not exist at this stage. Ignore | Include | Test => unreachable!(), - // render given-declarations properly - Context => todo!(), } } diff --git a/compiler/driver/src/cli.rs b/compiler/driver/src/cli.rs index fbf28145..cb53d29b 100644 --- a/compiler/driver/src/cli.rs +++ b/compiler/driver/src/cli.rs @@ -435,7 +435,7 @@ impl TypedValueParser for ColorModeParser { ) -> Result { let source = parse_utf8(source)?; - source.parse().map_err(|_| { + source.parse().map_err(|()| { // @Task smh. avoid using `Error::raw` and smh. pass along the context. // https://github.com/clap-rs/clap/discussions/4029 clap::Error::raw( @@ -700,7 +700,7 @@ impl TypedValueParser for WordParser { ) -> Result { let source = parse_utf8(source)?; - Word::parse(source.to_owned()).map_err(|_| { + Word::parse(source.to_owned()).map_err(|()| { // @Task smh. avoid using `Error::raw` and smh. pass along the context. // https://github.com/clap-rs/clap/discussions/4029 clap::Error::raw( @@ -726,7 +726,7 @@ impl TypedValueParser for ComponentTypeParser { let source = parse_utf8(source)?; // @Task smh. also support the shorthands (e.g. `exe`, `lib`) - source.parse().map_err(|_| { + source.parse().map_err(|()| { // @Task smh. avoid using `Error::raw` and smh. pass along the context. // https://github.com/clap-rs/clap/discussions/4029 clap::Error::raw( @@ -757,7 +757,7 @@ impl TypedValueParser for BackendParser { ) -> Result { let source = parse_utf8(source)?; - source.parse().map_err(|_| { + source.parse().map_err(|()| { // @Task smh. avoid using `Error::raw` and smh. pass along the context. // https://github.com/clap-rs/clap/discussions/4029 clap::Error::raw( @@ -1064,7 +1064,7 @@ mod unstable { } impl From<()> for ParseError { - fn from(_: ()) -> Self { + fn from((): ()) -> Self { Self::UndefinedOption } } diff --git a/compiler/hir/src/lib.rs b/compiler/hir/src/lib.rs index 5f5108bd..2538939f 100644 --- a/compiler/hir/src/lib.rs +++ b/compiler/hir/src/lib.rs @@ -3,7 +3,7 @@ use diagnostics::{error::PossiblyErroneous, reporter::ErasedReportedError}; use joinery::JoinableIterator; -use span::SourceFileIndex; +use span::{SourceFileIndex, Spanned}; use special::NumericType; use std::{ fmt, @@ -109,17 +109,18 @@ pub type Expression = Item; #[derive(Clone)] pub enum BareExpression { - PiType(Box), - Application(Box>), Number(Box), Text(Box), Binding(Box), - Lambda(Box), - CaseAnalysis(Box), - Substituted(Box), + Application(Box>), IntrinsicApplication(Box), + Record(Box), Projection(Box), + PiType(Box), + Lambda(Box), IO(Box), + CaseAnalysis(Box), + Substituted(Box), Error(ErasedReportedError), } @@ -224,6 +225,24 @@ impl From for BareExpression { } } +#[derive(Clone)] +pub struct Record { + pub type_: Spanned, + pub fields: Vec, +} + +impl From for BareExpression { + fn from(record: Record) -> Self { + Self::Record(Box::new(record)) + } +} + +#[derive(Clone)] +pub struct Field { + pub binder: ast::Identifier, + pub body: Expression, +} + #[derive(Clone)] pub struct Projection { pub basis: Expression, diff --git a/compiler/hir_format/src/lib.rs b/compiler/hir_format/src/lib.rs index 2afdc4fa..c4c46084 100644 --- a/compiler/hir_format/src/lib.rs +++ b/compiler/hir_format/src/lib.rs @@ -267,6 +267,8 @@ fn write_lower_expression( write_lower_expression(&projection.basis, session, f)?; write!(f, "::{}", projection.field) } + // @Task + Record(_record) => f.write_str("⟨record⟩"), IO(io) => { // @Temporary format write!(f, "⟨io {}", io.index)?; @@ -538,26 +540,26 @@ impl ComponentExt for Component { ) -> String { let entity = &self[index]; // @Task rewrite this recursive approach to an iterative one! - if let Some(parent) = entity.parent { - let mut parent_path = self.local_index_with_root_to_extern_path(parent, root); + let Some(parent) = entity.parent else { + return root; + }; - let parent_is_symbol = parent_path.chars().next_back().unwrap().is_symbol(); + let mut parent_path = self.local_index_with_root_to_extern_path(parent, root); - if parent_is_symbol { - parent_path.push(' '); - } + let parent_is_symbol = parent_path.chars().next_back().unwrap().is_symbol(); - parent_path.push('.'); + if parent_is_symbol { + parent_path.push(' '); + } - if entity.source.is_symbol() && parent_is_symbol { - parent_path.push(' '); - } + parent_path.push('.'); - parent_path += entity.source.to_str(); - parent_path - } else { - root + if entity.source.is_symbol() && parent_is_symbol { + parent_path.push(' '); } + + parent_path += entity.source.to_str(); + parent_path } fn local_index_to_path_segments( diff --git a/compiler/hir_format/src/test.rs b/compiler/hir_format/src/test.rs index 4b0b7fd4..585d46de 100644 --- a/compiler/hir_format/src/test.rs +++ b/compiler/hir_format/src/test.rs @@ -721,7 +721,7 @@ fn attributes() { .into(), ), &session, - ) + ); } #[test] diff --git a/compiler/lexer/src/test.rs b/compiler/lexer/src/test.rs index e8157632..924d8552 100644 --- a/compiler/lexer/src/test.rs +++ b/compiler/lexer/src/test.rs @@ -26,6 +26,7 @@ macro assert_lex_eq { } #[track_caller] +#[allow(clippy::needless_pass_by_value)] // more legible call sites, flexibility doesn't matter here fn assert_eq(actual: Outcome, expected: Outcome) { assert!( actual == expected, @@ -98,7 +99,7 @@ it", Token::new(span(23, 25), Word("it".into())), Token::new(span(25, 25), EndOfInput), ], - ) + ); } #[test] @@ -157,7 +158,7 @@ fn shebang_lookalike_not_first_line() { Token::new(span(23, 24), LineBreak), Token::new(span(24, 24), EndOfInput), ], - ) + ); } #[test] @@ -248,7 +249,7 @@ fn identifier_with_trailing_dot() { Token::new(span(10, 11), Dot), Token::new(span(11, 11), EndOfInput), ], - ) + ); } #[test] @@ -261,7 +262,7 @@ fn identifier_dot_symbol() { Token::new(span(11, 14), Symbol("+>!".into())), Token::new(span(14, 14), EndOfInput), ], - ) + ); } #[test] @@ -274,7 +275,7 @@ fn lex_identifier_dot_dotted_symbol() { Token::new(span(11, 16), Symbol("$.?!.".into())), Token::new(span(16, 16), EndOfInput), ], - ) + ); } #[test] @@ -286,7 +287,7 @@ fn lex_identifier_and_dotted_symbol_after_space() { Token::new(span(11, 17), Symbol(".$.?!.".into())), Token::new(span(17, 17), EndOfInput), ], - ) + ); } #[test] @@ -299,7 +300,7 @@ fn lex_keyword_dot_symbol() { Token::new(span(6, 7), Symbol("#".into())), Token::new(span(7, 7), EndOfInput), ], - ) + ); } #[test] @@ -648,7 +649,7 @@ of Token::new(span(18, 18), LineBreak), Token::new(span(18, 18), EndOfInput), ], - ) + ); } #[test] @@ -773,7 +774,7 @@ fn brackets_reset_indentation() { Token::new(span(20, 21), LineBreak), Token::new(span(21, 21), EndOfInput), ], - ) + ); } #[test] diff --git a/compiler/lo_ast/src/attribute.rs b/compiler/lo_ast/src/attribute.rs index 31df1c0d..a84a9937 100644 --- a/compiler/lo_ast/src/attribute.rs +++ b/compiler/lo_ast/src/attribute.rs @@ -96,7 +96,7 @@ pub enum ParentDeclarationKind { impl Target for ast::Expression { type Context = (); - fn name(&self, _: ()) -> &'static str { + fn name(&self, (): ()) -> &'static str { use ast::BareExpression::*; match &self.bare { @@ -121,7 +121,7 @@ impl Target for ast::Expression { } } - fn targets(&self, _: ()) -> Targets { + fn targets(&self, (): ()) -> Targets { use ast::BareExpression::*; match self.bare { @@ -147,7 +147,7 @@ impl Target for ast::Expression { impl Target for ast::Pattern { type Context = (); - fn name(&self, _: ()) -> &'static str { + fn name(&self, (): ()) -> &'static str { use ast::BarePattern::*; match self.bare { @@ -162,7 +162,7 @@ impl Target for ast::Pattern { } } - fn targets(&self, _: ()) -> Targets { + fn targets(&self, (): ()) -> Targets { use ast::BarePattern::*; match self.bare { @@ -371,7 +371,7 @@ pub enum BareAttribute { /// Make the declaration available in the context. /// /// Not part of the surface language. - /// Used by the lowered form of given-declarations. + /// Produced by the lowering of given-declarations. Context, /// Deny a [lint](Lint). /// @@ -455,7 +455,7 @@ pub enum BareAttribute { /// location <0:path:Text-Literal> /// ``` Location { path: Atom }, - /// Mark a data type binding to be likely expanded in the number of constructors. + /// Mark a data type to be likely expanded in the number of constructors. Moving, /// Make the binding part of the public API or at least visible in modules higher up. /// @@ -467,6 +467,11 @@ pub enum BareAttribute { /// public [<0:reach:Path>] /// Public(Public), + /// Mark a data type as a record or trait. + /// + /// Not part of the surface language. + /// Produced by the lowering of record and trait declarations. + Record, /// Define the recursion limit of the TWI. /// /// # Form @@ -482,6 +487,11 @@ pub enum BareAttribute { Statistics, /// Mark a function as a unit test. Test, + /// Mark a data type as a trait. + /// + /// Not part of the surface language. + /// Produced by the lowering of trait declarations. + Trait, /// Mark a binding or expression as "unsafe". Unsafe, /// Mark a binding as an unstable part of the public API. @@ -516,7 +526,7 @@ impl BareAttribute { } Intrinsic { .. } => Targets::FUNCTION_DECLARATION | Targets::DATA_DECLARATION, Include => Targets::TEXT_LITERAL, - Known { .. } | Moving | Abstract => Targets::DATA_DECLARATION, + Known { .. } | Moving | Abstract | Record | Trait => Targets::DATA_DECLARATION, // @Task for constructors, smh add extra diagnostic note saying they are public automatically // @Update with `@transparent` implemented, suggest `@transparent` on the data decl Public { .. } => { @@ -575,9 +585,11 @@ impl fmt::Display for BareAttribute { | Self::Ignore | Self::Include | Self::Moving + | Self::Record | Self::Static | Self::Statistics | Self::Test + | Self::Trait | Self::Unsafe => write!(f, "{name}"), Self::Allow { lint } diff --git a/compiler/lo_ast/src/format.rs b/compiler/lo_ast/src/format.rs index 5e1b6906..6cb92cdd 100644 --- a/compiler/lo_ast/src/format.rs +++ b/compiler/lo_ast/src/format.rs @@ -238,18 +238,12 @@ fn write_pi_type_literal_or_lower( f.write_str("{")?; let mut fields = record.fields.bare.iter(); if let Some(field) = fields.next() { - write!(f, "{}", field.name)?; - if let Some(expression) = &field.item { - f.write_str(" = ")?; - expression.write(f)?; - } + write!(f, "{} = ", field.binder)?; + field.body.write(f)?; } for field in fields { - write!(f, ", {}", field.name)?; - if let Some(expression) = &field.item { - f.write_str(" = ")?; - expression.write(f)?; - } + write!(f, ", {} = ", field.binder)?; + field.body.write(f)?; } f.write_str("}") } diff --git a/compiler/lo_ast/src/lib.rs b/compiler/lo_ast/src/lib.rs index e60b1484..321b4ed6 100644 --- a/compiler/lo_ast/src/lib.rs +++ b/compiler/lo_ast/src/lib.rs @@ -3,11 +3,11 @@ #![allow(incomplete_features)] // adt_const_params use ast::{ - Identifier, LocalBinder, NumberLiteral, ParameterKind, Path, RecordLiteral, SequenceLiteral, - TextLiteral, Wildcard, + Identifier, LocalBinder, NumberLiteral, ParameterKind, Path, SequenceLiteral, TextLiteral, + Wildcard, }; use diagnostics::{error::PossiblyErroneous, reporter::ErasedReportedError}; -use span::SourceFileIndex; +use span::{SourceFileIndex, Spanned}; pub use attribute::{Attribute, AttributeName, Attributes, BareAttribute}; pub use format::Display; @@ -334,5 +334,19 @@ pub struct Application { pub argument: T, } +#[derive(Clone)] +pub struct RecordLiteral { + pub path: Option, + pub fields: Spanned>>, + pub base: Option, +} + +#[derive(Clone)] + +pub struct Field { + pub binder: Identifier, + pub body: T, +} + #[derive(Clone, Copy)] pub struct DeBruijnLevel(pub usize); diff --git a/compiler/lowerer/src/attribute.rs b/compiler/lowerer/src/attribute.rs index 7d6a229f..a6473bdf 100644 --- a/compiler/lowerer/src/attribute.rs +++ b/compiler/lowerer/src/attribute.rs @@ -322,6 +322,7 @@ impl BareAttributeExt for lo_ast::BareAttribute { Self::Public(lo_ast::attribute::Public { reach }) } + Record => Self::Record, RecursionLimit => { let depth = argument(arguments, attribute.span, session.reporter())?; let depth = depth @@ -346,6 +347,7 @@ impl BareAttributeExt for lo_ast::BareAttribute { Static => Self::Static, Statistics => Self::Statistics, Test => Self::Test, + Trait => Self::Trait, Unsafe => Self::Unsafe, Unstable => { return Err(AttributeParsingError::Erased( diff --git a/compiler/lowerer/src/declaration.rs b/compiler/lowerer/src/declaration.rs index da7cb73c..20945d33 100644 --- a/compiler/lowerer/src/declaration.rs +++ b/compiler/lowerer/src/declaration.rs @@ -8,6 +8,12 @@ use lo_ast::{ use span::{PossiblySpanning, Span, Spanned, Spanning}; use utility::{default, smallvec, Atom, FormatError, SmallVec, FILE_EXTENSION}; +// @Bug trait lowering is incorrect but it can't easily be fixed (the synthesized field accessors can refer to each +// other order independently and the constructor can refer to them too by accident if it refers to fields that are +// out of order or ones that should be undefined) +// @Bug further, the lowering of records, traits (and maybe givens, too) is super useless for the type-checker +// it doesn't simplify things at all + impl Lowerer<'_> { pub(crate) fn lower_declaration( &mut self, @@ -39,15 +45,7 @@ impl Lowerer<'_> { function.into(), )] } - Data(type_) => { - let type_ = self.lower_data(*type_, &attributes, declaration.span); - - smallvec![lo_ast::Declaration::new( - attributes, - declaration.span, - type_.into() - )] - } + Data(type_) => smallvec![self.lower_data(*type_, attributes, declaration.span)], Given(given) => smallvec![self.lower_given(*given, attributes, declaration.span)], Module(module) => { smallvec![self.lower_module(*module, attributes, declaration.span, inline_modules)] @@ -135,10 +133,10 @@ impl Lowerer<'_> { fn lower_data( &mut self, data_type: ast::Data, - attributes: &Attributes, + mut attributes: Attributes, span: Span, - ) -> lo_ast::Data { - self.check_data_body(&data_type, attributes, span); + ) -> lo_ast::Declaration { + self.check_data_body(&data_type, &attributes, span); let type_ = match data_type.type_ { Some(type_) => self.lower_expression(type_), @@ -168,11 +166,28 @@ impl Lowerer<'_> { } }); - lo_ast::Data { - binder: data_type.binder, - type_, - declarations, + if let ast::DataKind::Record | ast::DataKind::Trait = data_type.kind { + attributes + .0 + .push(Spanned::new(span, lo_ast::BareAttribute::Record)); } + + if let ast::DataKind::Trait = data_type.kind { + attributes + .0 + .push(Spanned::new(span, lo_ast::BareAttribute::Trait)); + } + + lo_ast::Declaration::new( + attributes, + span, + lo_ast::Data { + binder: data_type.binder, + type_, + declarations, + } + .into(), + ) } fn check_data_body(&mut self, type_: &ast::Data, attributes: &Attributes, span: Span) { @@ -464,7 +479,7 @@ the body containing a set of constructors ); // @Beacon @Task don't re-lower type_constructor params! (here, in lower_fields & in lower_data) - for parameter in type_constructor_parameters.clone() { + for parameter in type_constructor_parameters.clone().into_iter().rev() { let domain = self.lower_parameter_type_with_default( parameter.bare.type_, parameter.bare.kind, @@ -565,9 +580,9 @@ the body containing a set of constructors body, ); - Some(ast::Field { - name: field.binder, - item: Some(body), + Some(lo_ast::Field { + binder: field.binder, + body, }) } _ => { @@ -585,7 +600,7 @@ the body containing a set of constructors lo_ast::Expression::common( body, - ast::RecordLiteral { + lo_ast::RecordLiteral { fields: Spanned::new(body, fields), path: None, base: None, diff --git a/compiler/lowerer/src/expression.rs b/compiler/lowerer/src/expression.rs index 8d68a103..2543dcbc 100644 --- a/compiler/lowerer/src/expression.rs +++ b/compiler/lowerer/src/expression.rs @@ -96,16 +96,20 @@ impl Lowerer<'_> { RecordLiteral(record) => lo_ast::Expression::new( attributes, expression.span, - ast::RecordLiteral { + lo_ast::RecordLiteral { path: record.path, fields: record.fields.map(|fields| { fields .into_iter() - .map(|field| ast::Field { - name: field.name, - item: field - .item - .map(|expression| self.lower_expression(expression)), + .map(|field| lo_ast::Field { + binder: field.binder, + body: field.body.map_or( + lo_ast::Expression::common( + field.binder.span(), + ast::Path::from(field.binder).into(), + ), + |expression| self.lower_expression(expression), + ), }) .collect() }), diff --git a/compiler/main/src/main.rs b/compiler/main/src/main.rs index 7cb127a0..e06f43fb 100644 --- a/compiler/main/src/main.rs +++ b/compiler/main/src/main.rs @@ -2,7 +2,7 @@ use std::process::ExitCode; fn main() -> ExitCode { match driver::main() { - Ok(_) => ExitCode::SUCCESS, + Ok(()) => ExitCode::SUCCESS, Err(_) => ExitCode::FAILURE, } } diff --git a/compiler/package/src/lib.rs b/compiler/package/src/lib.rs index f05158e0..3344ff15 100644 --- a/compiler/package/src/lib.rs +++ b/compiler/package/src/lib.rs @@ -749,7 +749,7 @@ fn parse_component_name_from_file_path(path: &Path, reporter: &Reporter) -> Resu // @Task do not unwrap! provide custom error let name = name.to_str().unwrap(); - Word::parse(name.into()).map_err(|_| { + Word::parse(name.into()).map_err(|()| { // @Task DRY @Question is the common code justified? // @Question isn't this function used in such a way that it's // "component and package name"? diff --git a/compiler/package/src/manifest.rs b/compiler/package/src/manifest.rs index cd92dff0..8e886e83 100644 --- a/compiler/package/src/manifest.rs +++ b/compiler/package/src/manifest.rs @@ -63,7 +63,7 @@ fn parse_name( ) -> Result> { Word::parse(name.clone()) .map(|name| Spanned::new(span, name)) - .map_err(|_| { + .map_err(|()| { // @Task DRY, @Question is the common code justified? package v component Diagnostic::error() .code(ErrorCode::E036) @@ -154,7 +154,7 @@ fn parse_component_type( ) -> Result, ErasedReportedError> { ComponentType::from_str(&type_) .map(|type_| Spanned::new(span, type_)) - .map_err(|_| { + .map_err(|()| { // @Task don't list all component types unconditionally: // if the invalid type is_similar to a valid one, give a more // fine-tuned suggestion @@ -207,7 +207,7 @@ fn parse_dependencies( let Spanned!(span, name) = name.with_text_content_span(map); DependencyProvider::from_str(&name) .map(|name| Spanned::new(span, name)) - .map_err(|_| { + .map_err(|()| { // @Task code // @Task don't list all providers unconditionally: // if the invalid provider is_similar to a valid one, give a more diff --git a/compiler/parser/src/common.rs b/compiler/parser/src/common.rs index 2152b692..3e7ff6d8 100644 --- a/compiler/parser/src/common.rs +++ b/compiler/parser/src/common.rs @@ -342,14 +342,14 @@ impl Parser<'_> { break; } - let name = self.parse_word()?; - let mut item = None; + let binder = self.parse_word()?; + let mut body = None; if self.consume(Equals) { - item = Some(self.parse_item()?); + body = Some(self.parse_item()?); } - fields.push(ast::Field { name, item }); + fields.push(ast::Field { binder, body }); if self.consume(Semicolon) { base = Some(self.parse_item()?); diff --git a/compiler/parser/src/lib.rs b/compiler/parser/src/lib.rs index f6acff30..143d9b72 100644 --- a/compiler/parser/src/lib.rs +++ b/compiler/parser/src/lib.rs @@ -62,7 +62,7 @@ pub fn parse_root_module_file( .to_str() .unwrap(); - let binder = Word::parse(name.to_owned()).map_err(|_| { + let binder = Word::parse(name.to_owned()).map_err(|()| { Diagnostic::error() .code(ErrorCode::E036) .message(format!( @@ -98,7 +98,6 @@ pub fn parse_path( map: &SourceMap, reporter: &Reporter, ) -> Result { - #[allow(clippy::redundant_closure_for_method_calls)] // false positive, #9335 parse(tokens, |parser| parser.parse_path(), file, map, reporter) } diff --git a/compiler/parser/src/test.rs b/compiler/parser/src/test.rs index cf5422c0..b03f832e 100644 --- a/compiler/parser/src/test.rs +++ b/compiler/parser/src/test.rs @@ -61,7 +61,7 @@ fn parse_declaration(source: &str) -> Result { ) } -/// The name of the module returned by [parse_declaration]. +/// The name of the module returned by [`parse_declaration`]. fn test_module_name() -> Identifier { identifier("test", default()) } @@ -121,7 +121,7 @@ fn identifier(name: &str, span: Span) -> Identifier { Identifier::new_unchecked(span, name.into()) } -/// Compare with [application_lambda_literal_argument_strict_grouping]. +/// Compare with [`application_lambda_literal_argument_strict_grouping`]. /// They parse to the same AST modulo spans. #[test] fn application_lambda_literal_argument_lax_grouping() { @@ -164,7 +164,7 @@ fn application_lambda_literal_argument_lax_grouping() { ); } -/// Compare with [application_lambda_literal_argument_lax_grouping]. +/// Compare with [`application_lambda_literal_argument_lax_grouping`]. /// They parse to the same AST modulo spans. #[test] fn application_lambda_literal_argument_strict_grouping() { @@ -274,7 +274,7 @@ fn bracketed_pi_type_literal_application_bracketed_argument_domain() { /// Compare this with `f Int -> Type`. /// /// This should demonstrate why we don't want `'A -> Type` to mean `'(_: A) -> Type`. -/// Compare this with [application_pi_type_literal_implicit_domain], too. +/// Compare this with [`application_pi_type_literal_implicit_domain`], too. #[test] fn pi_type_literal_application_implicit_argument_domain() { assert_eq( @@ -339,7 +339,7 @@ fn pi_type_literal_application_implicit_named_argument_domain() { ); } -/// Compare with [pi_type_literal_application_implicit_argument_domain]. +/// Compare with [`pi_type_literal_application_implicit_argument_domain`]. #[test] fn application_pi_type_literal_implicit_domain() { assert_eq( @@ -420,7 +420,7 @@ fn namespaced_base_with_field() { ); } -/// Compare with [base_with_attribute_and_field]. +/// Compare with [`base_with_attribute_and_field`]. #[test] fn field_with_attribute() { assert_eq( @@ -443,7 +443,7 @@ fn field_with_attribute() { ); } -/// Compare with [field_with_attribute]. +/// Compare with [`field_with_attribute`]. #[test] fn base_with_attribute_and_field() { assert_eq( @@ -625,7 +625,6 @@ lengthy-space-filler (case 0 of // @Task add test (here or as golden) for expression `f (a = g b)` (this couldn't be parsed until now // because of a bug; only `f (a = (g b))` was valid) -/// Compare with [use_as_double_brackets]. #[test] fn use_as_plain() { assert_eq( @@ -657,10 +656,10 @@ fn use_as_plain() { } .into(), )), - ) + ); } -/// Compare with [unindented_case_analysis]. They are identical up to span. +/// Compare with [`unindented_case_analysis`]. They are identical up to span. #[test] fn indented_case_analysis() { assert_eq( @@ -734,7 +733,7 @@ main = ); } -/// Compare with [indented_case_analysis]. They are identical up to span. +/// Compare with [`indented_case_analysis`]. They are identical up to span. #[test] fn unindented_case_analysis() { assert_eq( @@ -815,7 +814,7 @@ fn pattern_with_attributes() { vec![Attribute::new( span(1, 4), BareAttribute::Regular { - binder: identifier("it".into(), span(2, 4)), + binder: identifier("it", span(2, 4)), arguments: SmallVec::new(), }, )], @@ -823,7 +822,7 @@ fn pattern_with_attributes() { ast::Application { callee: Pattern::common( span(6, 9), - Path::from(identifier("has".into(), span(6, 9))).into(), + Path::from(identifier("has", span(6, 9))).into(), ), kind: Explicit, binder: None, @@ -831,15 +830,15 @@ fn pattern_with_attributes() { vec![Attribute::new( span(10, 13), BareAttribute::Regular { - binder: identifier("IT".into(), span(11, 13)), + binder: identifier("IT", span(11, 13)), arguments: SmallVec::new(), }, )], span(14, 17), - Path::from(identifier("HAS".into(), span(14, 17))).into(), + Path::from(identifier("HAS", span(14, 17))).into(), ), } .into(), )), - ) + ); } diff --git a/compiler/resolver/src/lib.rs b/compiler/resolver/src/lib.rs index 56ef6f5f..de7ecfdb 100644 --- a/compiler/resolver/src/lib.rs +++ b/compiler/resolver/src/lib.rs @@ -867,13 +867,15 @@ impl<'a> Resolver<'a> { ) } SequenceLiteral(sequence) => { - let mut elements = Vec::new(); + let mut elements = Vec::with_capacity(sequence.elements.bare.len()); + let health = &mut Health::Untainted; for element in sequence.elements.bare { - // @Task use Stain::stain to not return early! - elements.push(self.resolve_expression(element, scope)?); + elements.push(self.resolve_expression(element, scope).stain(health)); } + Result::from(*health)?; + self.resolve_sequence_literal( hir::Item::new( expression.attributes, @@ -886,11 +888,46 @@ impl<'a> Resolver<'a> { scope, )? } - RecordLiteral(_) => { - return Err(Diagnostic::error() - .message("record literals are not supported yet") - .unlabeled_span(expression.span) - .report(self.session.reporter())) + RecordLiteral(record) => { + let path = record.path.as_ref().ok_or_else(|| { + error::unqualified_literal("record", record.fields.span) + .report(self.session.reporter()) + })?; + + // @Task maybe check if it points to a record! + let type_ = Spanned::new( + path.span(), // @Task use the span of the last segment for consistency + self.resolve_path_of_literal(path, record.fields.span, scope)?, + ); + + if let Some(base) = record.base { + let error = Diagnostic::error() + .message("record literal bases are not supported yet") + .unlabeled_span(base.span) + .report(self.session.reporter()); + + let _ = self.resolve_expression(base, scope)?; + + return Err(error); + } + + let mut fields = Vec::with_capacity(record.fields.bare.len()); + let health = &mut Health::Untainted; + + for field in record.fields.bare { + fields.push(hir::Field { + binder: field.binder, + body: self.resolve_expression(field.body, scope).stain(health), + }); + } + + Result::from(*health)?; + + hir::Expression::new( + expression.attributes, + expression.span, + hir::Record { type_, fields }.into(), + ) } Error(error) => PossiblyErroneous::error(error), }) @@ -1003,7 +1040,7 @@ impl<'a> Resolver<'a> { .as_ref() .map(|path| { Ok(Spanned::new( - path.span(), + path.span(), // @Task use the span of the last segment for consistency self.resolve_path_of_literal(path, number.bare.literal.span, scope)?, )) }) @@ -1056,7 +1093,7 @@ impl<'a> Resolver<'a> { .as_ref() .map(|path| { Ok(Spanned::new( - path.span(), + path.span(), // @Task use the span of the last segment for consistency self.resolve_path_of_literal(path, text.bare.literal.span, scope)?, )) }) @@ -1096,15 +1133,12 @@ impl<'a> Resolver<'a> { // @Task test this! let path = sequence.bare.path.as_ref().ok_or_else(|| { - Diagnostic::error() - .message("sequence literals without explicit type are not supported yet") - .unlabeled_span(&sequence.bare.elements) - .help("consider prefixing the literal with a path to a type followed by a ‘.’") + error::unqualified_literal("sequence", sequence.bare.elements.span) .report(self.session.reporter()) })?; let type_ = Spanned::new( - path.span(), + path.span(), // @Task use the span of the last segment for consistency self.resolve_path_of_literal(path, sequence.bare.elements.span, scope)?, ); @@ -1430,7 +1464,7 @@ impl<'a> Resolver<'a> { }; // @Beacon @Task add test for error case - let component: Spanned = (*component).try_into().map_err(|_| { + let component: Spanned = (*component).try_into().map_err(|()| { // @Task DRY @Question is the common code justified? Diagnostic::error() .code(ErrorCode::E036) @@ -2493,4 +2527,13 @@ mod error { )) .unlabeled_spans(cycle.into_iter().map(|&index| session[index].source.span())) } + + pub(super) fn unqualified_literal(kind: &'static str, span: Span) -> Diagnostic { + Diagnostic::error() + .message(format!( + "{kind} literals without explicit type are not supported yet" + )) + .unlabeled_span(span) + .help("consider prefixing the literal with a path to a type followed by a ‘.’") + } } diff --git a/compiler/server/src/lib.rs b/compiler/server/src/lib.rs index 9ca97946..20629f13 100644 --- a/compiler/server/src/lib.rs +++ b/compiler/server/src/lib.rs @@ -124,6 +124,7 @@ impl Server { // @Task replace the async tower_lsp library with a sync server. async is not worth it #[tower_lsp::async_trait] +#[allow(clippy::ignored_unit_patterns)] // false positive impl tower_lsp::LanguageServer for Server { async fn initialize(&self, _: InitializeParams) -> jsonrpc::Result { Ok(InitializeResult { @@ -466,6 +467,7 @@ impl FindBinding for hir::Expression { Substituted(_) => None, // @Task IntrinsicApplication(_) => None, // @Task Projection(_) => None, // @Task + Record(_) => None, // @Task IO(_) => None, // @Task Error(_) => None, // @Task } diff --git a/compiler/session/src/package.rs b/compiler/session/src/package.rs index 3600cfe4..f8ab9531 100644 --- a/compiler/session/src/package.rs +++ b/compiler/session/src/package.rs @@ -56,7 +56,7 @@ pub enum PossiblyUnresolvedComponent { pub struct ManifestPath(pub internment::Intern); impl ManifestPath { - pub const FILE_NAME: &str = "package.recnot"; + pub const FILE_NAME: &'static str = "package.recnot"; pub fn folder(&self) -> &CanonicalPath { self.0.parent().unwrap() diff --git a/compiler/span/src/source_map/test.rs b/compiler/span/src/source_map/test.rs index c2dfddf8..9da1b34b 100644 --- a/compiler/span/src/source_map/test.rs +++ b/compiler/span/src/source_map/test.rs @@ -387,17 +387,19 @@ fn lines_highlight_containing_trailing_line_break() { } #[test] -#[should_panic] +#[should_panic(expected = "not yet implemented")] #[ignore = "panicking on invalid spans is currently not guaranteed"] fn lines_span_out_of_bounds_single_line_source() { let mut map = SourceMap::default(); map.add_str(Anonymous, "abcdefghi\n"); map.lines_with_highlight(span(6, 20)); + + todo!() } #[test] -#[should_panic] +#[should_panic(expected = "called `Option::unwrap()` on a `None` value")] fn lines_span_out_of_bounds_single_line_source_no_trailing_line_break() { let mut map = SourceMap::default(); map.add_str(Anonymous, "abcdefghi"); @@ -406,7 +408,7 @@ fn lines_span_out_of_bounds_single_line_source_no_trailing_line_break() { } #[test] -#[should_panic] +#[should_panic(expected = "not yet implemented")] #[ignore = "panicking on invalid spans is currently not guaranteed"] fn lines_span_out_of_bounds_multi_line_source() { let mut map = SourceMap::default(); @@ -416,7 +418,7 @@ fn lines_span_out_of_bounds_multi_line_source() { } #[test] -#[should_panic] +#[should_panic(expected = "called `Option::unwrap()` on a `None` value")] fn lines_span_out_of_bounds_multi_line_source_no_trailing_line_break() { let mut map = SourceMap::default(); map.add_str(Anonymous, "abc\ndefghi"); @@ -425,7 +427,7 @@ fn lines_span_out_of_bounds_multi_line_source_no_trailing_line_break() { } #[test] -#[should_panic] +#[should_panic(expected = "called `Option::unwrap()` on a `None` value")] fn lines_span_out_of_bounds_empty_source() { let mut map = SourceMap::default(); map.add_str(Anonymous, ""); @@ -435,7 +437,7 @@ fn lines_span_out_of_bounds_empty_source() { // @Task implement this #[test] -#[should_panic] +#[should_panic(expected = "not yet implemented")] #[ignore = "unimplemented"] fn lines_span_does_not_start_at_char_boundary() { todo!() @@ -443,7 +445,7 @@ fn lines_span_does_not_start_at_char_boundary() { // @Task implement this #[test] -#[should_panic] +#[should_panic(expected = "not yet implemented")] #[ignore = "unimplemented"] fn lines_span_does_not_end_at_char_boundary() { todo!() diff --git a/compiler/typer/src/interpreter.rs b/compiler/typer/src/interpreter.rs index 3e690f90..a4ba8e60 100644 --- a/compiler/typer/src/interpreter.rs +++ b/compiler/typer/src/interpreter.rs @@ -173,7 +173,8 @@ impl<'a> Interpreter<'a> { } } Number(_) | Text(_) | IO(_) => expression.clone(), - Projection(_) => todo!(), + Record(_) => todo!("evaluating records"), + Projection(_) => todo!("evaluating projections"), PiType(pi) => match context.form { Form::Normal => { let domain = self.evaluate_expression(&pi.domain, context)?; @@ -571,10 +572,9 @@ impl Substitute for Expression { .substitute(&substituted0.substitution) .substitute(substituted1), (Number(_) | Text(_), _) => self.clone(), - // @Task verify - (Projection(_), _) => self.clone(), - // @Temporary - (IO(_), _) => self.clone(), + (Record(_), _) => todo!("subst'ing records"), + (Projection(_), _) => todo!("subst'ing projections"), + (IO(_), _) => todo!("subst'ing effects"), (Application(application), substitution) => Expression::new( self.attributes.clone(), self.span, diff --git a/compiler/typer/src/lib.rs b/compiler/typer/src/lib.rs index 70931bc8..69d37346 100644 --- a/compiler/typer/src/lib.rs +++ b/compiler/typer/src/lib.rs @@ -718,7 +718,35 @@ expected type ‘_ -> _’ // @Task IntrinsicApplication(_) => todo!("inferring the type of intrinsic applications"), // @Task - Projection(_) => todo!("inferring the type of projections"), + Projection(projection) => { + let _basis_type = self.infer_type_of_expression(&projection.basis, scope)?; + + // @Task check if the basis type is a record and if it has given field + // @Note somehow substitute stuff, consider + + // record R A of + // f: A + // main = R.{f = Nat.0}::f ;;; 0 : Nat + + // This might need unification + + todo!("inferring the type of projections") + } + // @Beacon @Beacon @Beacon @Bug unsound, check if the type is record type first! + // @Task type-check the fields, too! + Record(record) => { + // @Task check if `type_` is a record type + // @Task check if the fields are correct (amount, names, types) + + // @Note this is so ugly! + hir::Identifier::new( + record.type_.bare, + self.session[record.type_.bare] + .source + .respan(record.type_.span), + ) + .to_item() + } IO(_) => self .session .require_special(Type::IO, Some(expression.span))? diff --git a/compiler/utility/src/cycle.rs b/compiler/utility/src/cycle.rs index bf6ca890..27044202 100644 --- a/compiler/utility/src/cycle.rs +++ b/compiler/utility/src/cycle.rs @@ -135,6 +135,8 @@ mod tests { #[test] fn empty_graph() { + #![allow(clippy::zero_sized_map_values)] // `Graph` is to be considered opaque + assert_eq!(find_cycles(&Graph::<()>::default()), Vec::new()); } diff --git a/compiler/utility/src/lib.rs b/compiler/utility/src/lib.rs index 95e68bc9..471b0965 100644 --- a/compiler/utility/src/lib.rs +++ b/compiler/utility/src/lib.rs @@ -84,8 +84,8 @@ pub macro try_all { pub macro condition($( $condition:expr => $consequence:expr ),+ $(, else => $alternative:expr )? $(,)?) { match () { - $( _ if $condition => $consequence, )+ - $( _ => $alternative )? + $( () if $condition => $consequence, )+ + $( () => $alternative )? } } diff --git a/project/library/recnot/src/parser/test.rs b/project/library/recnot/src/parser/test.rs index 85255fe7..ef17ba57 100644 --- a/project/library/recnot/src/parser/test.rs +++ b/project/library/recnot/src/parser/test.rs @@ -18,6 +18,7 @@ fn parse(source: &str) -> Result { super::super::parse(file, &map, &reporter) } +#[allow(clippy::needless_pass_by_value)] // more legible call sites, flexibility doesn't matter here fn assert_eq(actual: Result, expected: Value) { match actual { Ok(actual) => { diff --git a/project/tool/ui_test_framework/src/cli.rs b/project/tool/ui_test_framework/src/cli.rs index 511cef79..5629f4f5 100644 --- a/project/tool/ui_test_framework/src/cli.rs +++ b/project/tool/ui_test_framework/src/cli.rs @@ -222,7 +222,7 @@ impl TypedValueParser for DiffViewParser { ) -> Result { let source: &str = parse_utf8(source)?; - source.parse().map_err(|_| { + source.parse().map_err(|()| { // @Task smh. avoid using `Error::raw` and smh. pass along the context. // https://github.com/clap-rs/clap/discussions/4029 clap::Error::raw( diff --git a/project/tool/ui_test_framework/src/configuration.rs b/project/tool/ui_test_framework/src/configuration.rs index c824d1bf..5ed5cc81 100644 --- a/project/tool/ui_test_framework/src/configuration.rs +++ b/project/tool/ui_test_framework/src/configuration.rs @@ -315,7 +315,7 @@ fn parse_parameter(mut source: Spanned<&str>, type_: TestType) -> Result, type_: TestType) -> Result { let mode = source .bare .parse() - .map_err(|_| Error::new(format!("‘{source}’ is not a valid test mode"), source.span))?; + .map_err(|()| Error::new(format!("‘{source}’ is not a valid test mode"), source.span))?; #[allow(clippy::match_same_arms)] match (type_, mode) { diff --git a/project/tool/ui_test_framework/src/configuration/tests.rs b/project/tool/ui_test_framework/src/configuration/tests.rs index 07a2b2ea..2d0067e4 100644 --- a/project/tool/ui_test_framework/src/configuration/tests.rs +++ b/project/tool/ui_test_framework/src/configuration/tests.rs @@ -167,7 +167,7 @@ fn parse_parameter_missing_argument_compiler_env_var_0() { span(0, 0) )), parse_parameter("compiler-env-var", SourceFile) - ) + ); } #[test] @@ -178,7 +178,7 @@ fn parse_parameter_missing_argument_compiler_env_var_1() { span(0, 0) )), parse_parameter("compiler-env-var BACKTRACE", SourceFile) - ) + ); } #[test] @@ -186,7 +186,7 @@ fn parse_parameter_invalid_argument() { assert_eq!( Err(Error::new("‘no’ is not a valid duration", span(0, 0))), parse_parameter("timeout no", SourceFile) - ) + ); } #[test] @@ -208,7 +208,7 @@ fn parse_parameter_too_many_arguments_pass() { span(0, 0) )), parse_parameter("pass check -Zinternals --no-core --tlib", SourceFile) - ) + ); } #[test] @@ -355,7 +355,7 @@ fn parse_configuration_unsupported_substitution() { span(1, 40) )), parse_configuration( - r#";;; TEST substitution DIR path/to/(\w+)"#, + r";;; TEST substitution DIR path/to/(\w+)", SourceFile, &mut SourceMap::default() ), diff --git a/project/tool/ui_test_framework/src/main.rs b/project/tool/ui_test_framework/src/main.rs index 2830a2ed..832eea6f 100644 --- a/project/tool/ui_test_framework/src/main.rs +++ b/project/tool/ui_test_framework/src/main.rs @@ -24,8 +24,8 @@ mod summary; fn main() -> ExitCode { match try_main() { - Ok(_) => ExitCode::SUCCESS, - Err(_) => ExitCode::FAILURE, + Ok(()) => ExitCode::SUCCESS, + Err(()) => ExitCode::FAILURE, } }