Skip to content

Commit

Permalink
Merge pull request #979 from hash-org/fix-548
Browse files Browse the repository at this point in the history
  • Loading branch information
feds01 authored Sep 15, 2023
2 parents ac1a72a + c6ebf0b commit 1c6e379
Show file tree
Hide file tree
Showing 18 changed files with 712 additions and 54 deletions.
3 changes: 2 additions & 1 deletion compiler/hash-driver/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ impl<I: CompilerInterface> Driver<I> {
// bootstrap
if self.compiler.diagnostics().iter().any(|r| r.is_error()) {
panic!(
"failed to bootstrap compiler: {}",
"failed to bootstrap compiler:\n{}",
Reporter::from_reports(self.compiler.diagnostics().to_owned())
);
}
Expand Down Expand Up @@ -312,6 +312,7 @@ impl<I: CompilerInterface> Driver<I> {
// we can print the diagnostics here
if self.compiler.settings().emit_errors
&& (!self.compiler.diagnostics().is_empty() || result.is_err())
&& !source.is_prelude()
{
self.emit_diagnostics();
}
Expand Down
5 changes: 3 additions & 2 deletions compiler/hash-error-codes/src/error_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ error_codes! {
UnsupportedTraits = 57,

// Pattern errors
IdentifierBoundMultipleTimes = 80,
MissingPatternBounds = 81,
MismatchingPatBind = 79,
DuplicateBindInPat = 80,
MissingPatBind = 81,
RefutablePat = 82,
NonExhaustiveMatch = 83,
InvalidRangePatBoundaries = 84,
Expand Down
46 changes: 45 additions & 1 deletion compiler/hash-semantics/src/diagnostics/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use hash_tir::tir::{SymbolId, TermId};
use hash_typecheck::errors::TcError;
use hash_utils::thin_vec::ThinVec;

use crate::passes::resolution::scoping::ContextKind;
use crate::passes::resolution::{pat_binds::Bind, scoping::ContextKind};

pub type SemanticResult<T> = Result<T, SemanticError>;

Expand Down Expand Up @@ -83,6 +83,50 @@ pub enum SemanticError {

/// An entry point was not found in the entry module.
EntryPointNotFound,

/// When a bind within a pattern is duplicated, e.g.
/// ```
/// match (1, 2) {
/// (a, a) => {}
/// }
/// ```
DuplicateBindInPat {
/// The secondary mention of the bind.
offending: Bind,

/// The bind that was originally specified
original: Bind,
},

/// Within an `or` pattern, where there is a discrepancy between the
/// declared bounds within two patterns. For example:
/// ```
/// match 2 {
/// a | b => {}
/// }
/// ```
MissingPatBind {
/// The span of the pattern that is missing the bind.
offending: Span,

/// The bind that is missing from the alternative.
missing: Bind,
},

/// When an alternative pattern contains bindings that are
/// declared inconsistently, e.g.
/// ```
/// match (1, 2) {
/// (mut t, a) | (t, a)
/// }
/// ```
MismatchingPatBind {
/// The offending binding that is mismatched.
offending: Bind,

/// The original binding that was specified in the alternative.
original: Bind,
},
}

impl From<TcError> for SemanticError {
Expand Down
35 changes: 34 additions & 1 deletion compiler/hash-semantics/src/diagnostics/reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ impl SemanticReporter {
SemanticError::ModulePatternsNotSupported { location } => {
let error = reporter
.error()
.code(HashErrorCode::MissingPatternBounds)
.code(HashErrorCode::MissingPatBind)
.title("module patterns are not supported yet");

error
Expand All @@ -257,6 +257,39 @@ impl SemanticReporter {
);
}
SemanticError::ExhaustivenessError { error } => error.add_to_reports(reporter),
SemanticError::DuplicateBindInPat { offending, original } => {
reporter
.error()
.code(HashErrorCode::DuplicateBindInPat)
.title(format!(
"variable `{}` is bound more than once in the same pattern",
original.name()
))
.add_labelled_span(offending.span(), "used in a pattern more than once")
.add_labelled_span(original.span(), "first binding of variable");
}
SemanticError::MissingPatBind { offending, missing } => {
reporter
.error()
.code(HashErrorCode::MissingPatBind)
.title(format!("variable `{}` is not bound in all patterns", missing.name()))
.add_labelled_span(
*offending,
format!("pattern doesn't bind `{}`", missing.name()),
)
.add_labelled_span(missing.span(), "variable not in all patterns");
}
SemanticError::MismatchingPatBind { original, offending } => {
reporter
.error()
.code(HashErrorCode::MismatchingPatBind)
.title(format!(
"variable `{}` is bound inconsistently across or-patterns",
original.name()
))
.add_labelled_span(original.span(), "first binding of variable")
.add_labelled_span(offending.span(), "bound differently");
}
}
}
}
8 changes: 5 additions & 3 deletions compiler/hash-semantics/src/passes/resolution/exprs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,8 @@ impl<E: SemanticEnv> ResolutionPass<'_, E> {
self.scoping().register_declaration(node);

// Pattern
let pat = self.try_or_add_error(self.make_pat_from_ast_pat(node.pat.ast_ref()));
let pat =
self.try_or_add_error(self.make_pat_from_ast_pat_and_check_binds(node.pat.ast_ref()));

// Inner expression:
let value = match node.value.as_ref() {
Expand Down Expand Up @@ -620,8 +621,9 @@ impl<E: SemanticEnv> ResolutionPass<'_, E> {
.iter()
.filter_map(|case| {
self.scoping().enter_match_case(case.ast_ref(), |stack_id| {
let bind_pat = self
.try_or_add_error(self.make_pat_from_ast_pat(case.pat.ast_ref()));
let bind_pat = self.try_or_add_error(
self.make_pat_from_ast_pat_and_check_binds(case.pat.ast_ref()),
);
let value = self.try_or_add_error(
self.make_term_from_ast_expr(case.expr.ast_ref()),
);
Expand Down
11 changes: 10 additions & 1 deletion compiler/hash-semantics/src/passes/resolution/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ use hash_ast::ast;
use hash_source::SourceId;
use hash_utils::derive_more::Deref;

use self::scoping::{ContextKind, Scoping};
use self::{
pat_binds::PatBindsChecker,
scoping::{ContextKind, Scoping},
};
use super::{analysis_pass::AnalysisPass, ast_info::AstInfo};
use crate::{diagnostics::definitions::SemanticResult, env::SemanticEnv, progress::AnalysisStage};

pub mod defs;
pub mod exprs;
pub mod params;
pub(crate) mod pat_binds;
pub mod paths;
pub mod pats;
pub mod scoping;
Expand Down Expand Up @@ -97,6 +101,11 @@ impl<'env, E: SemanticEnv + 'env> ResolutionPass<'env, E> {
Self { env, scoping: Scoping::new(env, ast_info), ast_info }
}

/// Get a new pattern binder checker.
fn pat_binds_validator(&self) -> PatBindsChecker<E> {
PatBindsChecker::new(self.env)
}

/// Get access to the current scoping state and operations.
fn scoping(&self) -> &Scoping<E> {
&self.scoping
Expand Down
Loading

0 comments on commit 1c6e379

Please sign in to comment.