Skip to content

Commit

Permalink
Closure & variable declaration fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
kaleidawave committed Mar 20, 2024
1 parent b6e9b80 commit a891b69
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 73 deletions.
1 change: 0 additions & 1 deletion checker/definitions/full.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,6 @@ declare function context_id_chain(): void;
@Constant
declare function satisfies<T>(t: T): T;


@Constant
declare function compile_type_to_object<T>(): any;
// ↑↑ Ezno Functions ↑↑
19 changes: 1 addition & 18 deletions checker/specification/specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ a = 3;
let a = 2;
```

- Cannot assign to variable 'a' before initialisation
- Cannot assign to 'a' before declaration

#### Assignment to non-existent variable

Expand Down Expand Up @@ -2064,23 +2064,6 @@ callFunction<string>(a => {

- Expected number, found string

#### Returning a function

> Yes, returns another function
```ts
type ExpectedFunction = () => ((a: string) => string)

const x: ExpectedFunction = function () {
return function (b) {
b satisfies number;
return b
}
}
```

- Expected number, found string

### Object constraint

> Any references to a annotated variable **must** be within its LHS type. These test that it carries down to objects.
Expand Down
6 changes: 3 additions & 3 deletions checker/specification/staging.md
Original file line number Diff line number Diff line change
Expand Up @@ -418,12 +418,12 @@ This contains new features (which don't have)
#### Comments as type annotations

```ts
function x(a /* : string */) {
function x(a /** string */) {
a satisfies number
}

const c /* : number */ = "5"
const c /** number */ = "5"
```

- Expected number, found string
- Cannot assign "5" to type number
- Type "5" is not assignable to type number
15 changes: 12 additions & 3 deletions checker/src/context/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ impl<'a> Environment<'a> {
// Get without the effects
let variable_in_map = self.get_variable_unbound(variable_name);

if let Some((_, _, variable)) = variable_in_map {
if let Some((_, boundary, variable)) = variable_in_map {
match variable {
VariableOrImport::Variable { mutability, declared_at, context: _ } => {
match mutability {
Expand All @@ -514,6 +514,17 @@ impl<'a> Environment<'a> {
VariableMutability::Mutable { reassignment_constraint } => {
let variable = variable.clone();
let variable_site = *declared_at;
let variable_id = variable.get_id();

if boundary.is_none()
&& !self.get_chain_of_info().any(|info| {
info.variable_current_value.contains_key(&variable_id)
}) {
return Err(AssignmentError::TDZ(TDZ {
position: assignment_position,
variable_name: variable_name.to_owned(),
}));
}

if let Some(reassignment_constraint) = *reassignment_constraint {
// TODO tuple with position:
Expand Down Expand Up @@ -554,8 +565,6 @@ impl<'a> Environment<'a> {
}
}

let variable_id = variable.get_id();

self.info.events.push(Event::SetsVariable(
variable_id,
new_type,
Expand Down
5 changes: 4 additions & 1 deletion checker/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use source_map::{Span, SpanWithSource};
use crate::{
context::environment::ExpectedReturnType,
diagnostics::{
CannotRedeclareVariable, TypeCheckError, TypeCheckWarning, TypeStringRepresentation,
CannotRedeclareVariable, TypeCheckError, TypeCheckWarning, TypeStringRepresentation, TDZ,
},
events::{ApplicationResult, RootReference},
features::{
Expand Down Expand Up @@ -354,6 +354,8 @@ impl<T: ContextType> Context<T> {
}

/// Similar to [`Context::get_this_unbound`]
///
/// First `bool` is whether this variable is on [`Context<Root>`]
fn get_variable_unbound(
&self,
variable_name: &str,
Expand Down Expand Up @@ -1080,6 +1082,7 @@ pub enum AssignmentError {
value_type: TypeStringRepresentation,
assignment_position: SpanWithSource,
},
TDZ(TDZ),
}

/// Wraps logic
Expand Down
7 changes: 7 additions & 0 deletions checker/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,13 @@ mod defined_errors_and_warnings {
kind,
}
}
AssignmentError::TDZ(TDZ { variable_name, position }) => {
Diagnostic::Position {
reason: format!("Cannot assign to '{variable_name}' before declaration"),
position,
kind,
}
}
},
TypeCheckError::InvalidJSXAttribute {
attribute_name,
Expand Down
3 changes: 2 additions & 1 deletion checker/src/synthesis/hoisting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,12 +228,13 @@ pub(crate) fn hoist_statements<T: crate::ReadFromFS>(
}
}

// Second stage
// Second stage: variables and function type hoisting
for item in items {
match item {
StatementOrDeclaration::Statement(stmt) => {
if let Statement::VarVariable(stmt) = stmt {
for declaration in &stmt.declarations {
crate::utils::notify!("declaration.name {:?}", declaration.name);
let constraint = get_annotation_from_declaration(
declaration,
environment,
Expand Down
2 changes: 2 additions & 0 deletions checker/src/synthesis/type_annotations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,7 @@ pub(crate) fn comment_as_type_annotation<T: crate::ReadFromFS>(
annotation.get_position().with_source(source),
))
} else {
crate::utils::notify!("Failed comment as type annotation");
// TODO warning
None
}
Expand All @@ -525,6 +526,7 @@ pub(crate) fn get_annotation_from_declaration<
else if let parser::WithComment::PostfixComment(_item, possible_declaration, position) =
&declaration.name
{
crate::utils::notify!("Here {:?}", possible_declaration);
comment_as_type_annotation(
possible_declaration,
&position.with_source(environment.get_source()),
Expand Down
46 changes: 26 additions & 20 deletions checker/src/types/calling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@ struct FunctionLike {
pub(crate) function: FunctionId,
/// For generic calls
pub(crate) from: Option<TypeId>,
/// TODO WIP
pub(crate) _is_dependent: bool,
pub(crate) this_value: ThisValue,
}

Expand All @@ -82,22 +80,34 @@ pub fn call_type_handle_errors<T: crate::ReadFromFS, A: crate::ASTImplementation
}) = callable
{
if let Type::Object(..) = checking_data.types.get_type_by_id(this_passed) {
let prototype = environment
if let Some(object_constraint) = environment
.get_chain_of_info()
.find_map(|facts| facts.prototypes.get(&this_passed))
.copied();

// if let gens @ Some(_) = object_constraint_structure_generics {
// gens.cloned()
// } else
if prototype.is_some_and(|prototype| {
checking_data.types.lookup_generic_map.contains_key(&prototype)
}) {
crate::utils::notify!("Registering lookup for calling");

Some(StructureGenericArguments::LookUp { on: this_passed })
.find_map(|c| c.object_constraints.get(&this_passed).copied())
{
if let Type::Constructor(Constructor::StructureGenerics(
StructureGenerics { arguments, .. },
)) = checking_data.types.get_type_by_id(object_constraint)
{
crate::utils::notify!("Here");
Some(arguments.clone())
} else {
None
}
} else {
None
let prototype = environment
.get_chain_of_info()
.find_map(|facts| facts.prototypes.get(&this_passed))
.copied();

if prototype.is_some_and(|prototype| {
checking_data.types.lookup_generic_map.contains_key(&prototype)
}) {
crate::utils::notify!("Registering lookup for calling");

Some(StructureGenericArguments::LookUp { on: this_passed })
} else {
None
}
}
} else {
None
Expand Down Expand Up @@ -236,23 +246,19 @@ fn get_logical_callable_from_type(
function: *f,
from,
this_value: on.unwrap_or(ThisValue::UseParent),
// Hopefully
_is_dependent: true,
};
Ok(Logical::Pure(function))
}
Type::SpecialObject(SpecialObjects::Function(f, t)) => {
// Always from
Ok(Logical::Pure(FunctionLike {
_is_dependent: from.is_some(),
from: Some(from.unwrap_or(ty)),
function: *f,
this_value: on.unwrap_or(*t),
}))
}
Type::SpecialObject(SpecialObjects::ClassConstructor { constructor, .. }) => {
Ok(Logical::Pure(FunctionLike {
_is_dependent: from.is_some(),
from,
function: *constructor,
this_value: ThisValue::UseParent,
Expand Down
63 changes: 37 additions & 26 deletions checker/src/types/poly_types/generics/generic_type_arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,37 +78,42 @@ impl TypeArgumentStore for FunctionTypeArguments {
None
}

fn curry_arguments(&self, types: &mut TypeStore, id: TypeId) -> TypeId {
fn curry_arguments(&self, types: &mut TypeStore, on: TypeId) -> TypeId {
// TODO some types might not have parameters, but still need specialising so this here will miss things out
// types.get_type_by_id(id).get_parameters() {
// let arguments = parameters
// .into_iter()
// .map(|p| (p, (self.local_arguments.get(&p).copied().unwrap_or(p), self.call_site)))
// .collect();
let id = if self.local_arguments.is_empty() {
id
} else {
types.register_type(Type::Constructor(crate::types::Constructor::StructureGenerics(
StructureGenerics {
on: id,
arguments: StructureGenericArguments::ExplicitRestrictions(
self.local_arguments
.iter()
.map(|(on, arg)| (*on, (*arg, self.call_site)))
.collect(),
),
},
)))
};
if self.closure_ids.is_empty() {
id
if let Type::Object(crate::types::ObjectNature::RealDeal) | Type::SpecialObject(..) =
types.get_type_by_id(on)
{
if self.closure_ids.is_empty() {
on
} else {
types.register_type(Type::Constructor(
crate::types::Constructor::StructureGenerics(StructureGenerics {
on,
arguments: StructureGenericArguments::Closure(self.closure_ids.clone()),
}),
))
}
} else {
types.register_type(Type::Constructor(crate::types::Constructor::StructureGenerics(
StructureGenerics {
on: id,
arguments: StructureGenericArguments::Closure(self.closure_ids.clone()),
},
)))
if self.local_arguments.is_empty() {
on
} else {
types.register_type(Type::Constructor(
crate::types::Constructor::StructureGenerics(StructureGenerics {
on,
arguments: StructureGenericArguments::ExplicitRestrictions(
self.local_arguments
.iter()
.map(|(on, arg)| (*on, (*arg, self.call_site)))
.collect(),
),
}),
))
}
}
}

Expand All @@ -135,6 +140,11 @@ pub enum StructureGenericArguments {
/// The object that has a generic prototype
on: TypeId,
},
// /// TODO this shouldn't exist, but as there is no way to disce
// ClosuresAndGenerics {
// closures: Vec<ClosureId>,
// restrictions: TypeRestrictions,
// },
}

impl StructureGenericArguments {
Expand All @@ -155,8 +165,9 @@ impl StructureGenericArguments {
types: &TypeStore,
) -> Option<Vec<TypeId>> {
match self {
StructureGenericArguments::ExplicitRestrictions(s) => {
s.get(&under).map(|(ty, _)| vec![*ty])
// | Self::ClosuresAndGenerics { restrictions, .. } => {
StructureGenericArguments::ExplicitRestrictions(restrictions) => {
restrictions.get(&under).map(|(ty, _)| vec![*ty])
}
StructureGenericArguments::Closure(_) => None,
StructureGenericArguments::LookUp { on } => {
Expand Down

0 comments on commit a891b69

Please sign in to comment.