diff --git a/dmc-lib/src/ast/class.rs b/dmc-lib/src/ast/class.rs index 6d76153..b970d11 100644 --- a/dmc-lib/src/ast/class.rs +++ b/dmc-lib/src/ast/class.rs @@ -1,7 +1,7 @@ use crate::ast::constructor::Constructor; use crate::ast::field::Field; use crate::ast::function::Function; -use crate::diagnostic::Diagnostic; +use crate::diagnostic::{Diagnostic, SecondaryLabel}; use crate::source_range::SourceRange; use crate::symbol::class_symbol::ClassSymbol; use crate::symbol_table::{SymbolInsertError, SymbolTable}; @@ -48,6 +48,7 @@ impl Class { .insert_class_symbol(to_insert) .map_err(|e| match e { SymbolInsertError::AlreadyDeclared(already_declared) => { + let symbol = already_declared.symbol().borrow(); vec![ Diagnostic::new( &format!( @@ -57,6 +58,11 @@ impl Class { self.declared_name_source_range.start(), self.declared_name_source_range.end(), ) + .with_secondary_labels(&[SecondaryLabel::new( + symbol.declared_name_source_range().start(), + symbol.declared_name_source_range().end(), + Some("Symbol declared here.".to_string()), + )]) .with_reporter(file!(), line!()), ] } @@ -151,6 +157,10 @@ impl Class { .flatten() .for_each(|diagnostic| diagnostics.push(diagnostic)); + if !diagnostics.is_empty() { + return Err(diagnostics); + } + if let Some(constructor) = &mut self.constructor { match constructor.type_check(symbol_table) { Ok(_) => {} @@ -160,6 +170,10 @@ impl Class { } } + if !diagnostics.is_empty() { + return Err(diagnostics); + } + self.functions .iter_mut() .map(|function| function.type_check(symbol_table)) @@ -167,6 +181,10 @@ impl Class { .flatten() .for_each(|diagnostic| diagnostics.push(diagnostic)); + if !diagnostics.is_empty() { + return Err(diagnostics); + } + // We need to determine if fields are initialized or not (the latter is an error). // First phase: check all fields, then check constructor, leaving pending those things that // are fields <- initialized by constructor. Then circle back to fields and check all are @@ -199,6 +217,9 @@ impl Class { field.declared_name_source_range().start(), field.declared_name_source_range().end(), ) + .with_primary_label_message( + "Must be initialized in declaration or constructor.", + ) .with_reporter(file!(), line!()), ) } diff --git a/examples/basic_classes.dm b/examples/basic_classes.dm new file mode 100644 index 0000000..9d8eb88 --- /dev/null +++ b/examples/basic_classes.dm @@ -0,0 +1,20 @@ +class Foo + mut bar: Int = 42 + + ctor(_bar: Int) + end + + fn baz() -> Int + bar + end +end + +class Qux + fn foo() -> Foo + Foo(42) + end +end + +fn main() + let crash = Qux() +end \ No newline at end of file