Skip to content

Commit

Permalink
Check catch argument type annotation (#131)
Browse files Browse the repository at this point in the history
* Check catch argument type annotation (fixes #112)
  • Loading branch information
CharlesTaylor7 committed Apr 14, 2024
1 parent d86eafe commit 05031e2
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 7 deletions.
12 changes: 12 additions & 0 deletions checker/specification/specification.md
Expand Up @@ -1668,6 +1668,18 @@ try {

- Expected string, found 3

#### Catch annotation

```ts
try {
throw 3
} catch (err: string) {
console.log(err)
}
```

- Cannot catch type string because the try block throws 3

#### Object destructuring assignment

```ts
Expand Down
19 changes: 19 additions & 0 deletions checker/src/diagnostics.rs
Expand Up @@ -343,6 +343,12 @@ mod defined_errors_and_warnings {
expected: TypeStringRepresentation,
found: TypeStringRepresentation,
},
// catch type is not compatible with thrown type
CatchTypeDoesNotMatch {
at: SpanWithSource,
expected: TypeStringRepresentation,
found: TypeStringRepresentation,
},
Unsupported {
thing: &'static str,
at: SpanWithSource,
Expand Down Expand Up @@ -643,13 +649,26 @@ mod defined_errors_and_warnings {
position: returned_position,
kind,
},
TypeCheckError::CatchTypeDoesNotMatch {
expected,
found,
at,
} => Diagnostic::Position {
reason: format!(
"Cannot catch type {found} because the try block throws {expected}",

),
position: at,
kind,
},
TypeCheckError::TypeHasNoGenericParameters(name, position) => {
Diagnostic::Position {
reason: format!("Type '{name}' has no generic parameters",),
position,
kind,
}
}

TypeCheckError::InvalidComparison(_, _) => todo!(),
TypeCheckError::InvalidAddition(_, _) => todo!(),
TypeCheckError::InvalidUnaryOperation(_, _) => todo!(),
Expand Down
73 changes: 66 additions & 7 deletions checker/src/synthesis/statements.rs
Expand Up @@ -6,13 +6,16 @@ use super::{
};
use crate::{
context::{Scope, VariableRegisterArguments},
diagnostics::TypeCheckError,
diagnostics::{TypeCheckError, TypeStringRepresentation},
features::iteration::{synthesise_iteration, IterationBehavior},
subtyping::{type_is_subtype, BasicEquality},
synthesis::EznoParser,
CheckingData, Environment, TypeId,
};

use parser::{expressions::MultipleExpression, ASTNode, BlockOrSingleStatement, Statement};
use parser::{
expressions::MultipleExpression, ASTNode, BlockOrSingleStatement, Statement, TypeAnnotation,
};
use std::collections::HashMap;

pub type ExportedItems = HashMap<String, crate::features::variables::VariableOrImport>;
Expand Down Expand Up @@ -237,11 +240,22 @@ pub(super) fn synthesise_statement<T: crate::ReadFromFS>(
checking_data,
|environment, checking_data| {
if let Some((clause, ty_annotation)) = &stmt.exception_var {
let catch_variable_type = ty_annotation.as_ref().map(|annotation| {
synthesise_type_annotation(annotation, environment, checking_data)
});

// TODO subtype thrown here with catch_variable_type
let mut catch_variable_type = None;
if let Some(ty_annotation) = ty_annotation {
let catch_type_id = synthesise_type_annotation(
ty_annotation,
environment,
checking_data,
);
check_catch_type(
ty_annotation,
catch_type_id,
thrown_type,
environment,
checking_data,
);
catch_variable_type = Some(catch_type_id);
}

register_variable(
clause.get_ast_ref(),
Expand Down Expand Up @@ -274,6 +288,51 @@ pub(super) fn synthesise_statement<T: crate::ReadFromFS>(
}
}

fn check_catch_type<T>(
catch_annotation: &TypeAnnotation,
catch_type: TypeId,
thrown_type: TypeId,
environment: &mut Environment,
checking_data: &mut CheckingData<T, super::EznoParser>,
) {
let mut basic_equality = BasicEquality {
add_property_restrictions: false,
position: source_map::Nullable::NULL,
object_constraints: Default::default(),
allow_errors: false,
};
let result = type_is_subtype(
catch_type,
thrown_type,
&mut basic_equality,
environment,
&checking_data.types,
);

if let crate::subtyping::SubTypeResult::IsNotSubType(_) = result {
let expected = TypeStringRepresentation::from_type_id(
thrown_type,
environment,
&checking_data.types,
false,
);
let found = TypeStringRepresentation::from_type_id(
catch_type,
environment,
&checking_data.types,
false,
);

let at = catch_annotation.get_position().with_source(environment.get_source());

checking_data.diagnostics_container.add_error(TypeCheckError::CatchTypeDoesNotMatch {
at,
expected,
found,
});
}
}

/// Expects that this caller has already create a context for this to run in
fn synthesise_block_or_single_statement<T: crate::ReadFromFS>(
block_or_single_statement: &BlockOrSingleStatement,
Expand Down

0 comments on commit 05031e2

Please sign in to comment.