1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use source_map::SpanWithSource;

use crate::context::{environment::ContextLocation, AssignmentError};
use crate::{types::TypeId, CheckingData, VariableId};
use std::fmt::Debug;

/// A variable, that can be referenced. Can be a including class (prototypes) and functions
///
/// TODO constant variables with a fixed value
#[derive(Clone, Debug, binary_serialize_derive::BinarySerializable)]
pub enum VariableOrImport {
	Variable {
		/// Whether can be reassigned and what to
		mutability: VariableMutability,
		/// Location where variable is defined **ALSO UNIQUELY IDENTIFIES THE VARIABLE** as can
		/// be turned into a [VariableId]
		declared_at: SpanWithSource,
		context: ContextLocation,
	},
	MutableImport {
		of: VariableId,
		constant: bool,
		import_specified_at: SpanWithSource,
	},
	ConstantImport {
		to: Option<VariableId>,
		import_specified_at: SpanWithSource,
	},
}

impl VariableOrImport {
	pub(crate) fn get_id(&self) -> VariableId {
		match self {
			VariableOrImport::Variable { mutability: _, declared_at, .. } => {
				VariableId(declared_at.source, declared_at.start)
			}
			VariableOrImport::MutableImport { import_specified_at, .. }
			| VariableOrImport::ConstantImport { import_specified_at, .. } => {
				VariableId(import_specified_at.source, import_specified_at.start)
			}
		}
	}

	pub(crate) fn get_mutability(&self) -> VariableMutability {
		match self {
			VariableOrImport::Variable { mutability, .. } => *mutability,
			// TODO I think ?
			VariableOrImport::MutableImport { of: _, constant: _, import_specified_at: _ }
			| VariableOrImport::ConstantImport { to: _, import_specified_at: _ } => {
				VariableMutability::Constant
			}
		}
	}

	pub(crate) fn get_origin_variable_id(&self) -> VariableId {
		match self {
			VariableOrImport::Variable { declared_at: pos, .. }
			| VariableOrImport::ConstantImport { import_specified_at: pos, .. } => {
				VariableId(pos.source, pos.start)
			}
			VariableOrImport::MutableImport { of, .. } => *of,
		}
	}
}

/// Shallow mutability
#[derive(Copy, Clone, Debug, binary_serialize_derive::BinarySerializable)]
pub enum VariableMutability {
	Constant,
	Mutable { reassignment_constraint: Option<TypeId> },
}

#[derive(Clone, Debug)]
pub struct VariableWithValue(pub VariableOrImport, pub TypeId);

pub fn check_variable_initialization<T: crate::ReadFromFS, A: crate::ASTImplementation>(
	(variable_declared_type, variable_declared_pos): (TypeId, SpanWithSource),
	(expression_type, expression_declared_pos): (TypeId, SpanWithSource),
	environment: &mut crate::context::Environment,
	checking_data: &mut CheckingData<T, A>,
) {
	use crate::types::subtyping::{type_is_subtype, BasicEquality, SubTypeResult};

	let mut basic_subtyping =
		BasicEquality { add_property_restrictions: true, position: variable_declared_pos };

	let type_is_subtype = type_is_subtype(
		variable_declared_type,
		expression_type,
		&mut basic_subtyping,
		environment,
		&checking_data.types,
	);

	if let SubTypeResult::IsNotSubType(_matches) = type_is_subtype {
		let error = crate::diagnostics::TypeCheckError::AssignmentError(
			AssignmentError::DoesNotMeetConstraint {
				variable_type: crate::diagnostics::TypeStringRepresentation::from_type_id(
					variable_declared_type,
					&environment.as_general_context(),
					&checking_data.types,
					checking_data.options.debug_types,
				),
				variable_site: basic_subtyping.position,
				value_type: crate::diagnostics::TypeStringRepresentation::from_type_id(
					expression_type,
					&environment.as_general_context(),
					&checking_data.types,
					checking_data.options.debug_types,
				),
				value_site: expression_declared_pos,
			},
		);

		checking_data.diagnostics_container.add_error(error);
	}
}