use source_map::{SourceId, Span, SpanWithSource};
use std::collections::HashSet;
use crate::{
behavior::{
assignments::{Assignable, AssignmentKind, Reference},
functions,
modules::{Exported, ImportKind, NamePair},
operations::{
evaluate_logical_operation_with_expression,
evaluate_pure_binary_operation_handle_errors, MathematicalAndBitwise,
},
variables::{VariableMutability, VariableOrImport, VariableWithValue},
},
diagnostics::{NotInLoopOrCouldNotFindLabel, TypeCheckError, TypeStringRepresentation, TDZ},
events::{Event, RootReference},
subtyping::BasicEquality,
types::{
is_type_truthy_falsy,
properties::{PropertyKey, PropertyKind, PropertyValue},
subtyping::{type_is_subtype, SubTypeResult},
PolyNature, Type, TypeStore,
},
CheckingData, Decidable, Instance, RootContext, TypeCombinable, TypeId,
};
use super::{
calling::CheckThings, facts::Publicity, get_on_ctx, get_value_of_variable, AssignmentError,
ClosedOverReferencesInScope, Context, ContextType, Environment, GeneralContext,
SetPropertyError,
};
pub type ContextLocation = Option<String>;
#[derive(Debug)]
pub struct Syntax<'a> {
pub scope: Scope,
pub(super) parent: GeneralContext<'a>,
pub free_variables: HashSet<RootReference>,
pub closed_over_references: ClosedOverReferencesInScope,
pub location: ContextLocation,
}
impl<'a> ContextType for Syntax<'a> {
fn as_general_context(et: &Context<Self>) -> GeneralContext<'_> {
GeneralContext::Syntax(et)
}
fn get_parent(&self) -> Option<&GeneralContext<'_>> {
Some(&self.parent)
}
fn is_dynamic_boundary(&self) -> bool {
matches!(self.scope, Scope::Function { .. } | Scope::Looping { .. })
}
fn is_conditional(&self) -> bool {
matches!(self.scope, Scope::Conditional { .. })
}
fn get_closed_over_references(&mut self) -> Option<&mut ClosedOverReferencesInScope> {
Some(&mut self.closed_over_references)
}
fn get_exports(&mut self) -> Option<&mut Exported> {
if let Scope::Module { ref mut exported, .. } = self.scope {
Some(exported)
} else {
None
}
}
}
#[derive(Debug, Clone)]
pub enum FunctionScope {
ArrowFunction {
free_this_type: TypeId,
is_async: bool,
},
MethodFunction {
free_this_type: TypeId,
is_async: bool,
is_generator: bool,
},
Function {
is_generator: bool,
is_async: bool,
this_type: TypeId,
type_of_super: TypeId,
},
Constructor {
extends: bool,
type_of_super: Option<TypeId>,
this_object_type: TypeId,
},
}
pub type Label = Option<String>;
#[derive(Debug, Clone)]
pub enum Scope {
Function(FunctionScope),
InterfaceEnvironment {
this_constraint: TypeId,
},
FunctionAnnotation {},
Conditional {
antecedent: TypeId,
is_switch: Option<Label>,
},
Looping {
label: Label, },
TryBlock {},
Block {},
Module {
source: SourceId,
exported: Exported,
},
DefinitionModule {
source: SourceId,
},
TypeAlias,
StaticBlock {},
PassThrough {
source: SourceId,
},
}
impl<'a> Environment<'a> {
pub fn assign_to_assignable_handle_errors<
'b,
T: crate::ReadFromFS,
A: crate::ASTImplementation,
>(
&mut self,
lhs: Assignable,
operator: AssignmentKind,
expression: Option<&'b A::Expression<'b>>,
assignment_span: SpanWithSource,
checking_data: &mut CheckingData<T, A>,
) -> TypeId {
match lhs {
Assignable::Reference(reference) => {
fn get_reference<U: crate::ReadFromFS, A: crate::ASTImplementation>(
env: &mut Environment,
reference: Reference,
checking_data: &mut CheckingData<U, A>,
) -> TypeId {
match reference {
Reference::Variable(name, position) => {
env.get_variable_handle_error(&name, position, checking_data).unwrap().1
}
Reference::Property { on, with, publicity, span } => {
let get_property_handle_errors = env.get_property_handle_errors(
on,
publicity,
with,
checking_data,
span,
);
match get_property_handle_errors {
Ok(i) => i.get_value(),
Err(()) => TypeId::ERROR_TYPE,
}
}
}
}
fn set_reference<U: crate::ReadFromFS, A: crate::ASTImplementation>(
env: &mut Environment,
reference: Reference,
new: TypeId,
checking_data: &mut CheckingData<U, A>,
) -> Result<TypeId, SetPropertyError> {
match reference {
Reference::Variable(name, position) => Ok(env
.assign_to_variable_handle_errors(
name.as_str(),
position,
new,
checking_data,
)),
Reference::Property { on, with, publicity, span } => Ok(env
.set_property(
on,
publicity,
&with,
new,
&checking_data.types,
Some(span),
)?
.unwrap_or(new)),
}
}
fn set_property_error_to_type_check_error(
ctx: &GeneralContext,
error: SetPropertyError,
assignment_span: SpanWithSource,
types: &TypeStore,
new: TypeId,
) -> TypeCheckError<'static> {
match error {
SetPropertyError::NotWriteable => {
TypeCheckError::PropertyNotWriteable(assignment_span)
}
SetPropertyError::DoesNotMeetConstraint {
property_constraint,
reason: _,
} => TypeCheckError::AssignmentError(AssignmentError::PropertyConstraint {
property_constraint,
value_type: TypeStringRepresentation::from_type_id(
new, ctx, types, false,
),
assignment_position: assignment_span,
}),
}
}
match operator {
AssignmentKind::Assign => {
let new = A::synthesise_expression(
expression.unwrap(),
TypeId::ANY_TYPE,
self,
checking_data,
);
let result = set_reference(self, reference, new, checking_data);
match result {
Ok(ty) => ty,
Err(error) => {
let error = set_property_error_to_type_check_error(
&self.as_general_context(),
error,
assignment_span,
&checking_data.types,
new,
);
checking_data.diagnostics_container.add_error(error);
TypeId::ERROR_TYPE
}
}
}
AssignmentKind::PureUpdate(operator) => {
let reference_position = reference.get_position();
let existing = get_reference(self, reference.clone(), checking_data);
let expression = expression.unwrap();
let expression_pos =
A::expression_position(expression).with_source(self.get_source());
let rhs = A::synthesise_expression(
expression,
TypeId::ANY_TYPE,
self,
checking_data,
);
let new = evaluate_pure_binary_operation_handle_errors(
(existing, reference_position),
operator.into(),
(rhs, expression_pos),
checking_data,
self,
);
let result = set_reference(self, reference, new, checking_data);
match result {
Ok(ty) => ty,
Err(error) => {
let error = set_property_error_to_type_check_error(
&self.as_general_context(),
error,
assignment_span,
&checking_data.types,
new,
);
checking_data.diagnostics_container.add_error(error);
TypeId::ERROR_TYPE
}
}
}
AssignmentKind::IncrementOrDecrement(direction, return_kind) => {
let span = reference.get_position();
let existing = get_reference(self, reference.clone(), checking_data);
let new = evaluate_pure_binary_operation_handle_errors(
(existing, span),
match direction {
crate::behavior::assignments::IncrementOrDecrement::Increment => {
MathematicalAndBitwise::Add
}
crate::behavior::assignments::IncrementOrDecrement::Decrement => {
MathematicalAndBitwise::Subtract
}
}
.into(),
(TypeId::ONE, SpanWithSource::NULL_SPAN),
checking_data,
self,
);
let result = set_reference(self, reference, new, checking_data);
match result {
Ok(new) => match return_kind {
crate::behavior::assignments::AssignmentReturnStatus::Previous => {
existing
}
crate::behavior::assignments::AssignmentReturnStatus::New => new,
},
Err(error) => {
let error = set_property_error_to_type_check_error(
&self.as_general_context(),
error,
assignment_span,
&checking_data.types,
new,
);
checking_data.diagnostics_container.add_error(error);
TypeId::ERROR_TYPE
}
}
}
AssignmentKind::ConditionalUpdate(operator) => {
let _span = reference.get_position();
let existing = get_reference(self, reference.clone(), checking_data);
let expression = expression.unwrap();
let new = evaluate_logical_operation_with_expression(
existing,
operator,
expression,
checking_data,
self,
)
.unwrap();
let result = set_reference(self, reference, new, checking_data);
match result {
Ok(new) => new,
Err(error) => {
let error = set_property_error_to_type_check_error(
&self.as_general_context(),
error,
assignment_span,
&checking_data.types,
new,
);
checking_data.diagnostics_container.add_error(error);
TypeId::ERROR_TYPE
}
}
}
}
}
Assignable::ObjectDestructuring(_) => todo!(),
Assignable::ArrayDestructuring(_) => todo!(),
}
}
pub fn new_function<U, F, A>(
&mut self,
checking_data: &mut CheckingData<U, A>,
function: &F,
behavior: functions::FunctionRegisterBehavior<A>,
) -> crate::types::FunctionType
where
U: crate::ReadFromFS,
A: crate::ASTImplementation,
F: functions::SynthesisableFunction<A>,
{
functions::register_function(self, behavior, function, checking_data)
}
pub fn assign_to_variable_handle_errors<T: crate::ReadFromFS, A: crate::ASTImplementation>(
&mut self,
variable_name: &str,
assignment_position: SpanWithSource,
new_type: TypeId,
checking_data: &mut CheckingData<T, A>,
) -> TypeId {
let result = self.assign_to_variable(
variable_name,
assignment_position,
new_type,
&checking_data.types,
);
match result {
Ok(ok) => ok,
Err(error) => {
checking_data
.diagnostics_container
.add_error(TypeCheckError::AssignmentError(error));
TypeId::ERROR_TYPE
}
}
}
pub fn assign_to_variable(
&mut self,
variable_name: &str,
assignment_position: SpanWithSource,
new_type: TypeId,
store: &TypeStore,
) -> Result<TypeId, AssignmentError> {
let variable_in_map = self.get_variable_unbound(variable_name);
if let Some((_, _, variable)) = variable_in_map {
match variable {
VariableOrImport::Variable { mutability, declared_at, context: _ } => {
match mutability {
VariableMutability::Constant => {
Err(AssignmentError::Constant(*declared_at))
}
VariableMutability::Mutable { reassignment_constraint } => {
let variable = variable.clone();
if let Some(reassignment_constraint) = *reassignment_constraint {
let mut basic_subtyping = BasicEquality {
add_property_restrictions: false,
position: *declared_at,
};
let result = type_is_subtype(
reassignment_constraint,
new_type,
&mut basic_subtyping,
self,
store,
);
if let SubTypeResult::IsNotSubType(_mismatches) = result {
return Err(AssignmentError::DoesNotMeetConstraint {
variable_type: TypeStringRepresentation::from_type_id(
reassignment_constraint,
&self.as_general_context(),
store,
false,
),
value_type: TypeStringRepresentation::from_type_id(
new_type,
&self.as_general_context(),
store,
false,
),
variable_site: assignment_position,
value_site: assignment_position,
});
}
}
let variable_id = variable.get_id();
self.facts.events.push(Event::SetsVariable(
variable_id,
new_type,
assignment_position,
));
self.facts.variable_current_value.insert(variable_id, new_type);
Ok(new_type)
}
}
}
VariableOrImport::MutableImport { .. }
| VariableOrImport::ConstantImport { .. } => {
Err(AssignmentError::Constant(assignment_position))
}
}
} else {
crate::utils::notify!("Could say it is on the window here");
Err(AssignmentError::VariableNotFound {
variable: variable_name.to_owned(),
assignment_position,
})
}
}
pub(crate) fn get_root(&self) -> &RootContext {
match self.context_type.parent {
GeneralContext::Syntax(syntax) => syntax.get_root(),
GeneralContext::Root(root) => root,
}
}
#[must_use]
pub fn get_environment_type(&self) -> &Scope {
&self.context_type.scope
}
pub fn get_environment_type_mut(&mut self) -> &mut Scope {
&mut self.context_type.scope
}
#[must_use]
pub fn property_in(&self, on: TypeId, property: &PropertyKey) -> bool {
self.facts_chain().any(|facts| match facts.current_properties.get(&on) {
Some(v) => {
v.iter().any(
|(_, p, v)| if let PropertyValue::Deleted = v { false } else { p == property },
)
}
None => false,
})
}
pub fn delete_property(&mut self, on: TypeId, property: &PropertyKey) -> bool {
let existing = self.property_in(on, property);
let under = property.into_owned();
self.facts.current_properties.entry(on).or_default().push((
Publicity::Public,
under.clone(),
PropertyValue::Deleted,
));
self.facts.events.push(Event::Setter {
on,
under,
new: PropertyValue::Deleted,
initialization: false,
publicity: Publicity::Public,
position: None,
});
existing
}
pub(crate) fn get_parent(&self) -> GeneralContext {
match self.context_type.parent {
GeneralContext::Syntax(syn) => GeneralContext::Syntax(syn),
GeneralContext::Root(rt) => GeneralContext::Root(rt),
}
}
pub fn get_property(
&mut self,
on: TypeId,
publicity: Publicity,
property: PropertyKey,
types: &mut TypeStore,
with: Option<TypeId>,
position: SpanWithSource,
) -> Option<(PropertyKind, TypeId)> {
crate::types::properties::get_property(
on,
publicity,
property,
with,
self,
&mut CheckThings,
types,
position,
)
}
pub fn get_property_handle_errors<U: crate::ReadFromFS, A: crate::ASTImplementation>(
&mut self,
on: TypeId,
publicity: Publicity,
key: PropertyKey,
checking_data: &mut CheckingData<U, A>,
site: SpanWithSource,
) -> Result<Instance, ()> {
let get_property =
self.get_property(on, publicity, key.clone(), &mut checking_data.types, None, site);
if let Some((kind, result)) = get_property {
Ok(match kind {
PropertyKind::Getter => Instance::GValue(result),
PropertyKind::Generic | PropertyKind::Direct => Instance::RValue(result),
})
} else {
let types = &checking_data.types;
let ctx = &self.as_general_context();
checking_data.diagnostics_container.add_error(TypeCheckError::PropertyDoesNotExist {
property: match key {
PropertyKey::String(s) => {
crate::diagnostics::PropertyRepresentation::StringKey(s.to_string())
}
PropertyKey::Type(t) => crate::diagnostics::PropertyRepresentation::Type(
crate::types::printing::print_type(
t,
&checking_data.types,
&self.as_general_context(),
false,
),
),
},
on: crate::diagnostics::TypeStringRepresentation::from_type_id(
on, ctx, types, false,
),
site,
});
Err(())
}
}
pub fn get_variable_handle_error<U: crate::ReadFromFS, A: crate::ASTImplementation>(
&mut self,
name: &str,
position: SpanWithSource,
checking_data: &mut CheckingData<U, A>,
) -> Result<VariableWithValue, TypeId> {
let (in_root, crossed_boundary, og_var) = {
let this = self.get_variable_unbound(name);
if let Some((in_root, crossed_boundary, og_var)) = this {
(in_root, crossed_boundary, og_var.clone())
} else {
checking_data.diagnostics_container.add_error(
TypeCheckError::CouldNotFindVariable {
variable: name,
possibles: Default::default(),
position,
},
);
return Err(TypeId::ERROR_TYPE);
}
};
let reference = RootReference::Variable(og_var.get_id());
if let VariableOrImport::Variable { context: Some(ref context), .. } = og_var {
if let Some(ref current_context) = self.parents_iter().find_map(|a| {
if let GeneralContext::Syntax(syn) = a {
syn.context_type.location.clone()
} else {
None
}
}) {
if current_context != context {
checking_data.diagnostics_container.add_error(
TypeCheckError::VariableNotDefinedInContext {
variable: name,
expected_context: context,
current_context: current_context.clone(),
position,
},
);
return Err(TypeId::ERROR_TYPE);
}
}
}
if let (Some(_boundary), false) = (crossed_boundary, in_root) {
let based_on = match og_var.get_mutability() {
VariableMutability::Constant => {
let constraint = checking_data
.type_mappings
.variables_to_constraints
.0
.get(&og_var.get_origin_variable_id());
{
let current_value = get_value_of_variable(
self.facts_chain(),
og_var.get_id(),
None::<&crate::types::poly_types::FunctionTypeArguments>,
);
if let Some(current_value) = current_value {
let ty = checking_data.types.get_type_by_id(current_value);
if matches!(ty, Type::Function(..)) {
return Ok(VariableWithValue(og_var.clone(), current_value));
} else if let Type::RootPolyType(PolyNature::Open(_)) = ty {
return Ok(VariableWithValue(og_var.clone(), current_value));
} else if let Type::Constant(_) = ty {
return Ok(VariableWithValue(og_var.clone(), current_value));
}
crate::utils::notify!("Free variable!");
}
}
if let Some(constraint) = constraint {
*constraint
} else {
crate::utils::notify!("TODO record that parent variable is `any` here");
TypeId::ANY_TYPE
}
}
VariableMutability::Mutable { reassignment_constraint } => {
for p in self.parents_iter() {
if let Some(value) =
get_on_ctx!(p.facts.variable_current_value.get(&og_var.get_id()))
{
return Ok(VariableWithValue(og_var.clone(), *value));
}
if get_on_ctx!(p.context_type.is_dynamic_boundary()) {
break;
}
}
if let Some(constraint) = reassignment_constraint {
constraint
} else {
crate::utils::notify!("TODO record that parent variable is `any` here");
TypeId::ANY_TYPE
}
}
};
let mut value = None;
for event in &self.facts.events {
if let Event::ReadsReference {
reference: other_reference,
reflects_dependency: Some(dep),
position: _,
} = event
{
if reference == *other_reference {
value = Some(dep);
break;
}
}
}
let type_id = if let Some(value) = value {
*value
} else {
let ty = Type::RootPolyType(crate::types::PolyNature::FreeVariable {
reference: reference.clone(),
based_on,
});
let ty = checking_data.types.register_type(ty);
self.context_type.free_variables.insert(reference);
self.facts.events.push(Event::ReadsReference {
reference: RootReference::Variable(og_var.get_id()),
reflects_dependency: Some(ty),
position,
});
ty
};
Ok(VariableWithValue(og_var.clone(), type_id))
} else {
if let VariableOrImport::MutableImport { of, constant: false, import_specified_at: _ } =
og_var.clone()
{
let current_value = get_value_of_variable(
self.facts_chain(),
of,
None::<&crate::types::poly_types::FunctionTypeArguments>,
)
.expect("import not assigned yet");
return Ok(VariableWithValue(og_var.clone(), current_value));
}
let current_value = get_value_of_variable(
self.facts_chain(),
og_var.get_id(),
None::<&crate::types::poly_types::FunctionTypeArguments>,
);
if let Some(current_value) = current_value {
Ok(VariableWithValue(og_var.clone(), current_value))
} else {
checking_data.diagnostics_container.add_error(TypeCheckError::TDZ(TDZ {
variable_name: self.get_variable_name(og_var.get_id()).to_owned(),
position,
}));
Ok(VariableWithValue(og_var.clone(), TypeId::ERROR_TYPE))
}
}
}
pub(crate) fn new_conditional_context<T, A, R>(
&mut self,
condition: TypeId,
then_evaluate: impl FnOnce(&mut Environment, &mut CheckingData<T, A>) -> R,
else_evaluate: Option<impl FnOnce(&mut Environment, &mut CheckingData<T, A>) -> R>,
checking_data: &mut CheckingData<T, A>,
) -> R
where
A: crate::ASTImplementation,
R: TypeCombinable,
T: crate::ReadFromFS,
{
if let Decidable::Known(result) = is_type_truthy_falsy(condition, &checking_data.types) {
return if result {
then_evaluate(self, checking_data)
} else if let Some(else_evaluate) = else_evaluate {
else_evaluate(self, checking_data)
} else {
R::default()
};
}
let (truthy_result, truthy_events) = {
let mut truthy_environment = self.new_lexical_environment(Scope::Conditional {
antecedent: condition,
is_switch: None,
});
let result = then_evaluate(&mut truthy_environment, checking_data);
(result, truthy_environment.facts.events)
};
if let Some(else_evaluate) = else_evaluate {
let mut falsy_environment = self.new_lexical_environment(Scope::Conditional {
antecedent: checking_data.types.new_logical_negation_type(condition),
is_switch: None,
});
let falsy_result = else_evaluate(&mut falsy_environment, checking_data);
let combined_result =
R::combine(condition, truthy_result, falsy_result, &mut checking_data.types);
let falsy_events = falsy_environment.facts.events;
self.facts.events.push(Event::Conditionally {
condition,
events_if_truthy: truthy_events.into_boxed_slice(),
else_events: falsy_events.into_boxed_slice(),
position: None,
});
combined_result
} else {
self.facts.events.push(Event::Conditionally {
condition,
events_if_truthy: truthy_events.into_boxed_slice(),
else_events: Default::default(),
position: None,
});
truthy_result
}
}
pub fn throw_value(&mut self, value: TypeId, position: SpanWithSource) {
self.facts.events.push(Event::Throw(value, position));
}
pub fn return_value(&mut self, returned: TypeId, returned_position: SpanWithSource) {
self.facts.events.push(Event::Return { returned, returned_position });
}
pub fn add_continue(
&mut self,
label: Option<&str>,
position: Span,
) -> Result<(), NotInLoopOrCouldNotFindLabel> {
if let Some(carry) = self.find_label_or_conditional_count(label, true) {
self.facts.events.push(Event::Continue {
position: Some(position.with_source(self.get_source())),
carry,
});
Ok(())
} else {
Err(NotInLoopOrCouldNotFindLabel {
label: label.map(ToOwned::to_owned),
position: position.with_source(self.get_source()),
})
}
}
pub fn add_break(
&mut self,
label: Option<&str>,
position: Span,
) -> Result<(), NotInLoopOrCouldNotFindLabel> {
if let Some(carry) = self.find_label_or_conditional_count(label, false) {
self.facts.events.push(Event::Break {
position: Some(position.with_source(self.get_source())),
carry,
});
Ok(())
} else {
Err(NotInLoopOrCouldNotFindLabel {
label: label.map(ToOwned::to_owned),
position: position.with_source(self.get_source()),
})
}
}
pub fn set_property(
&mut self,
on: TypeId,
publicity: Publicity,
under: &PropertyKey,
new: TypeId,
types: &TypeStore,
setter_position: Option<SpanWithSource>,
) -> Result<Option<TypeId>, SetPropertyError> {
crate::types::properties::set_property(
on,
publicity,
under,
&PropertyValue::Value(new),
self,
&mut CheckThings,
types,
setter_position,
)
}
fn find_label_or_conditional_count(
&self,
looking_for_label: Option<&str>,
is_continue: bool,
) -> Option<u8> {
let mut falling_through_structures = 0;
for ctx in self.parents_iter() {
if let GeneralContext::Syntax(ctx) = ctx {
let scope = &ctx.context_type.scope;
match scope {
Scope::Function(_)
| Scope::InterfaceEnvironment { .. }
| Scope::FunctionAnnotation {}
| Scope::Module { .. }
| Scope::DefinitionModule { .. }
| Scope::TypeAlias
| Scope::StaticBlock {} => {
break;
}
Scope::Looping { ref label } => {
if looking_for_label.is_none() {
return Some(falling_through_structures);
} else if let Some(label) = label {
if label == looking_for_label.unwrap() {
return Some(falling_through_structures);
}
falling_through_structures += 1;
}
}
Scope::Conditional { is_switch: Some(_label @ Some(_)), .. }
if !is_continue && looking_for_label.is_some() =>
{
todo!("switch break")
}
Scope::PassThrough { .. }
| Scope::Conditional { .. }
| Scope::TryBlock {}
| Scope::Block {} => {}
}
}
}
None
}
pub(crate) fn import_items<
'b,
P: Iterator<Item = NamePair<'b>>,
T: crate::ReadFromFS,
A: crate::ASTImplementation,
>(
&mut self,
partial_import_path: &str,
import_position: Span,
default_import: Option<(&str, Span)>,
kind: ImportKind<'b, P>,
checking_data: &mut CheckingData<T, A>,
also_export: bool,
) {
let current_source = self.get_source();
if !matches!(self.context_type.scope, crate::Scope::Module { .. }) {
checking_data.diagnostics_container.add_error(TypeCheckError::NotTopLevelImport(
import_position.with_source(current_source),
));
return;
}
let exports = checking_data.import_file(current_source, partial_import_path, self);
if let Err(ref err) = exports {
checking_data.diagnostics_container.add_error(TypeCheckError::CannotOpenFile {
file: err.clone(),
position: Some(import_position.with_source(self.get_source())),
});
}
if let Some((default_name, position)) = default_import {
if let Ok(Ok(ref exports)) = exports {
if let Some(item) = &exports.default {
let id = crate::VariableId(current_source, position.start);
let v = VariableOrImport::ConstantImport {
to: None,
import_specified_at: position.with_source(current_source),
};
self.facts.variable_current_value.insert(id, *item);
let existing = self.variables.insert(default_name.to_owned(), v);
if let Some(_existing) = existing {
todo!("diagnostic")
}
} else {
todo!("emit 'no default export' diagnostic")
}
} else {
let behavior = crate::context::VariableRegisterBehavior::ConstantImport {
value: TypeId::ERROR_TYPE,
};
self.register_variable_handle_error(
default_name,
position.with_source(current_source),
behavior,
checking_data,
);
}
}
match kind {
ImportKind::Parts(parts) => {
for part in parts {
if let Ok(Ok(ref exports)) = exports {
if let Some(export) = exports.get_export(part.value) {
match export {
crate::behavior::modules::TypeOrVariable::ExportedVariable((
variable,
mutability,
)) => {
let constant = match mutability {
VariableMutability::Constant => {
let k = crate::VariableId(
current_source,
part.position.start,
);
let v = self
.get_value_of_constant_import_variable(variable);
self.facts.variable_current_value.insert(k, v);
true
}
VariableMutability::Mutable {
reassignment_constraint: _,
} => false,
};
let v = VariableOrImport::MutableImport {
of: variable,
constant,
import_specified_at: part
.position
.with_source(self.get_source()),
};
let existing = self.variables.insert(part.r#as.to_owned(), v);
if let Some(_existing) = existing {
todo!("diagnostic")
}
if also_export {
if let Scope::Module { ref mut exported, .. } =
self.context_type.scope
{
exported.named.push((
part.r#as.to_owned(),
(variable, mutability),
));
}
}
}
crate::behavior::modules::TypeOrVariable::Type(ty) => {
let existing =
self.named_types.insert(part.r#as.to_owned(), ty);
assert!(existing.is_none(), "TODO exception");
}
}
} else {
let position = part.position.with_source(current_source);
checking_data.diagnostics_container.add_error(
TypeCheckError::FieldNotExported {
file: partial_import_path,
position,
importing: part.value,
},
);
let behavior =
crate::context::VariableRegisterBehavior::ConstantImport {
value: TypeId::ERROR_TYPE,
};
self.register_variable_handle_error(
part.r#as,
position,
behavior,
checking_data,
);
}
} else {
let behavior = crate::context::VariableRegisterBehavior::ConstantImport {
value: TypeId::ERROR_TYPE,
};
self.register_variable_handle_error(
part.r#as,
part.position.with_source(current_source),
behavior,
checking_data,
);
}
}
}
ImportKind::All { under, position } => {
if let Ok(Ok(ref exports)) = exports {
let value = checking_data.types.register_type(Type::SpecialObject(
crate::behavior::objects::SpecialObjects::Import(exports.clone()),
));
self.register_variable_handle_error(
under,
position.with_source(current_source),
crate::context::VariableRegisterBehavior::ConstantImport { value },
checking_data,
);
} else {
let behavior = crate::context::VariableRegisterBehavior::Declare {
base: TypeId::ERROR_TYPE,
context: None,
};
self.register_variable_handle_error(
under,
position.with_source(current_source),
behavior,
checking_data,
);
}
}
ImportKind::Everything => {
if let Ok(Ok(ref exports)) = exports {
for (name, (variable, mutability)) in &exports.named {
if let Scope::Module { ref mut exported, .. } = self.context_type.scope {
exported.named.push((name.clone(), (*variable, *mutability)));
}
}
} else {
}
}
}
}
}