1use std::rc::Rc;
5
6use crate::{
7 ast::{ExprId, nodes::ExpressionKind, statements::TypeAnnotation},
8 checker::{TypeChecker, structs::CheckType},
9 utils::span::Span,
10};
11
12impl TypeChecker {
13 pub fn check_expression(&mut self, expression: ExprId) -> CheckType {
14 let expr_span = self.ast_arena.exprs.get(expression).span;
15 let expr_kind = self.ast_arena.exprs.get(expression).kind.clone();
16 match expr_kind {
17 ExpressionKind::Null => CheckType::Known(TypeAnnotation::Null),
19 ExpressionKind::Integer(_) => CheckType::Known(TypeAnnotation::Int),
20 ExpressionKind::Byte(_) => CheckType::Known(TypeAnnotation::Byte),
21 ExpressionKind::String(_) => CheckType::Known(TypeAnnotation::String),
22 ExpressionKind::Bool(_) => CheckType::Known(TypeAnnotation::Bool),
23 ExpressionKind::Float(_) => CheckType::Known(TypeAnnotation::Float),
24 ExpressionKind::Character(_) => CheckType::Known(TypeAnnotation::Char),
25 ExpressionKind::Grouping(inner) => self.check_expression(inner),
27 ExpressionKind::Identifier(name) => self.lookup(&name, expr_span),
29 ExpressionKind::MapLiteral(entries) => {
30 let mut key_types = Vec::with_capacity(entries.len());
31 let mut value_types = Vec::with_capacity(entries.len());
32 for (key, value) in entries {
33 let key_span = self.ast_arena.exprs.get(key).span;
34 let value_span = self.ast_arena.exprs.get(value).span;
35 key_types.push((self.check_expression(key), key_span));
36 value_types.push((self.check_expression(value), value_span));
37 }
38
39 let key_type = key_types
40 .first()
41 .map(|(t, _)| Self::to_type_annotation(t))
42 .unwrap_or(TypeAnnotation::Null);
43 let value_type = value_types
44 .first()
45 .map(|(t, _)| Self::to_type_annotation(t))
46 .unwrap_or(TypeAnnotation::Null);
47
48 if let Some((first_key, _)) = key_types.first().cloned() {
49 for (kt, span) in key_types.iter().skip(1) {
50 if !kt.is_null() && !first_key.is_null() && !kt.matches(&first_key) {
51 self.error(
52 format!(
53 "map key type mismatch: expected {}, got {}",
54 first_key.info(),
55 kt.info()
56 ),
57 *span,
58 );
59 }
60 }
61 }
62 if let Some((first_value, _)) = value_types.first().cloned() {
63 for (vt, span) in value_types.iter().skip(1) {
64 if !vt.is_null() && !first_value.is_null() && !vt.matches(&first_value) {
65 self.error(
66 format!(
67 "map value type mismatch: expected {}, got {}",
68 first_value.info(),
69 vt.info()
70 ),
71 *span,
72 );
73 }
74 }
75 }
76
77 for (kt, span) in &key_types {
78 if !kt.is_null() && !Self::is_hashable_key_type(&Self::to_type_annotation(kt)) {
79 self.error(
80 format!("type {} cannot be used as a map key", kt.info()),
81 *span,
82 );
83 }
84 }
85
86 CheckType::Known(TypeAnnotation::Map(
87 Box::new(key_type),
88 Box::new(value_type),
89 ))
90 }
91 ExpressionKind::ArrayLiteral(items) => {
93 let mut item_types = Vec::with_capacity(items.len());
96 for item in items {
97 let item_span = self.ast_arena.exprs.get(item).span;
98 item_types.push((self.check_expression(item), item_span));
99 }
100 let items_type = item_types
102 .first()
103 .map(|(t, _)| Self::to_type_annotation(t))
104 .unwrap_or(TypeAnnotation::Null);
105
106 if let Some((first_type, _)) = item_types.first().cloned() {
108 for (item_type, span) in item_types.iter().skip(1) {
109 if !item_type.is_null()
110 && !first_type.is_null()
111 && !item_type.matches(&first_type)
112 {
113 self.error(
114 format!(
115 "array element type mismatch: expected {}, got {}",
116 first_type.info(),
117 item_type.info()
118 ),
119 *span,
120 );
121 }
122 }
123 }
124 CheckType::Known(TypeAnnotation::Array(Box::new(items_type)))
126 }
127
128 ExpressionKind::Index { target, index } => {
129 let target_span = self.ast_arena.exprs.get(target).span;
131 let index_span = self.ast_arena.exprs.get(index).span;
132 let target_type = self.check_expression(target);
133 self.check_is_null(&target_type, target_span);
134 let index_type = self.check_expression(index);
136 self.check_is_null(&index_type, index_span);
137
138 let target_is_map = matches!(
142 target_type,
143 CheckType::Known(TypeAnnotation::Map(_, _) | TypeAnnotation::CMap(_, _))
144 );
145 if !target_is_map
146 && !matches!(
147 index_type,
148 CheckType::Known(
149 TypeAnnotation::Int
150 | TypeAnnotation::CInt
151 | TypeAnnotation::Byte
152 | TypeAnnotation::CByte
153 ) | CheckType::Unknown
154 )
155 {
156 self.error(
157 format!("invalid index operation: index is {}", index_type.info()),
158 expr_span,
159 );
160 }
161
162 match &target_type {
165 CheckType::Known(TypeAnnotation::Array(inner))
166 | CheckType::Known(TypeAnnotation::CArray(inner)) => {
167 CheckType::Known((**inner).clone())
168 }
169 CheckType::Known(TypeAnnotation::Set(inner))
170 | CheckType::Known(TypeAnnotation::CSet(inner)) => {
171 CheckType::Known((**inner).clone())
172 }
173 CheckType::Known(TypeAnnotation::Map(key_ty, value_ty))
174 | CheckType::Known(TypeAnnotation::CMap(key_ty, value_ty)) => {
175 let expected_key = CheckType::Known((**key_ty).clone());
176 if !index_type.matches(&expected_key) {
177 self.error(
178 format!(
179 "map key type mismatch: expected {}, got {}",
180 expected_key.info(),
181 index_type.info()
182 ),
183 index_span,
184 );
185 }
186 CheckType::Known((**value_ty).clone())
187 }
188 CheckType::Unknown | CheckType::Known(TypeAnnotation::Null) => {
189 CheckType::Unknown
190 }
191 CheckType::Known(TypeAnnotation::Tuple(_) | TypeAnnotation::CTuple(_)) => {
192 CheckType::Unknown
193 }
194 other => {
195 self.error(
196 format!("invalid index operation: this is {}", other.info()),
197 expr_span,
198 );
199 CheckType::Unknown
200 }
201 }
202 }
203
204 ExpressionKind::IndexAssign {
206 target,
207 index,
208 value,
209 } => self.check_index_assign(target, index, value, expr_span),
210
211 ExpressionKind::Binary {
213 left,
214 operator,
215 right,
216 } => {
217 let left_type = self.check_expression(left);
219 let left_id = self.ast_arena.exprs.get(left);
220 self.check_is_null(&left_type, left_id.span);
221 let right_type = self.check_expression(right);
223 let right_id = self.ast_arena.exprs.get(right);
224 self.check_is_null(&right_type, right_id.span);
225 self.check_binary_operator(left_type, right_type, &operator, expr_span)
227 }
228
229 ExpressionKind::Unary { operator, operand } => {
231 let operand_span = self.ast_arena.exprs.get(operand).span;
233 let operand_type = self.check_expression(operand);
234 self.check_is_null(&operand_type, operand_span);
235 self.check_unary_operator(operand_type, operand_span, &operator, expr_span)
237 }
238
239 ExpressionKind::Assign { name, value } => {
241 let value_type = self.check_expression(value);
242 self.assign(&name, value_type.clone(), expr_span);
243 value_type
244 }
245
246 ExpressionKind::Call { path, args } => {
248 let arg_types: Vec<(CheckType, Span)> = args
249 .iter()
250 .map(|a| {
251 let a = *a;
252 let a_span = self.ast_arena.exprs.get(a).span;
253 (self.check_expression(a), a_span)
254 })
255 .collect();
256 self.check_call_path(&path, &arg_types, expr_span)
257 }
258
259 ExpressionKind::CallExpr { callee, args } => {
261 let callee_type = self.check_expression(callee);
262 let arg_types: Vec<(CheckType, Span)> = args
263 .iter()
264 .map(|a| {
265 let a = *a;
266 let a_span = self.ast_arena.exprs.get(a).span;
267 (self.check_expression(a), a_span)
268 })
269 .collect();
270 self.check_call_value(callee_type, &arg_types, expr_span)
271 }
272
273 ExpressionKind::MethodCall {
275 caller,
276 method,
277 args,
278 } => {
279 let caller_type = self.check_expression(caller);
280 let caller_id = self.ast_arena.exprs.get(caller);
281 let mut arg_types: Vec<(CheckType, Span)> = vec![(caller_type, caller_id.span)];
282 for arg in args {
283 let arg_span = self.ast_arena.exprs.get(arg).span;
284 arg_types.push((self.check_expression(arg), arg_span));
285 }
286 self.check_call_path(&method, &arg_types, expr_span)
287 }
288
289 ExpressionKind::Lambda {
291 params,
292 return_type,
293 body,
294 } => {
295 let resolved_return = return_type.clone().unwrap_or(TypeAnnotation::Null);
297 self.push_scope();
299 for param in ¶ms {
301 self.declare(
302 param.param_name.clone(),
303 CheckType::Known(param.param_type.clone()),
304 false,
305 expr_span,
306 );
307 }
308 self.push_return_type(resolved_return.clone());
310 for statement in &body {
312 self.check_statement(statement);
313 }
314 self.pop_return_type();
316 self.pop_scope();
318
319 CheckType::Function {
320 params: params.iter().map(|p| p.param_type.clone()).collect(),
321 return_type: resolved_return,
322 }
323 }
324
325 ExpressionKind::Cast { value, target_type } => {
326 let value_type = self.check_expression(value);
327 let value_id = self.ast_arena.exprs.get(value);
328 self.check_is_null(&value_type, value_id.span);
329
330 let castable = matches!(
331 &value_type,
332 CheckType::Known(
333 TypeAnnotation::CInt
334 | TypeAnnotation::CByte
335 | TypeAnnotation::CFloat
336 | TypeAnnotation::Float
337 | TypeAnnotation::Int
338 | TypeAnnotation::Byte
339 ) | CheckType::Unknown
340 );
341
342 let valid_target = matches!(
343 target_type,
344 TypeAnnotation::Int | TypeAnnotation::Float | TypeAnnotation::Byte
345 );
346
347 if !castable || !valid_target {
348 self.error(
349 format!(
350 "invalid cast: cannot cast {} to {:?}",
351 value_type.info(),
352 target_type
353 ),
354 expr_span,
355 );
356 }
357 CheckType::Unknown
358 }
359
360 ExpressionKind::TupleLiteral(items) => {
361 let types: Vec<TypeAnnotation> = items
362 .iter()
363 .map(|item| {
364 let t = self.check_expression(*item);
365 Self::to_type_annotation(&t)
366 })
367 .collect();
368 CheckType::Known(TypeAnnotation::Tuple(Rc::new(types)))
369 }
370 ExpressionKind::ErrorLiteral(inner) => {
371 let inner_type = self.check_expression(inner);
372 if matches!(
373 inner_type,
374 CheckType::Known(TypeAnnotation::Error | TypeAnnotation::CError)
375 ) {
376 self.error("error cannot wrap another error", expr_span);
377 }
378 CheckType::Known(TypeAnnotation::Error)
379 }
380 ExpressionKind::OkLiteral(inner) => {
381 let inner_ann = Self::to_type_annotation(&self.check_expression(inner));
382 CheckType::Known(TypeAnnotation::Result(Box::new(inner_ann)))
383 }
384 ExpressionKind::ErrLiteral(inner) => {
385 let inner_ann = Self::to_type_annotation(&self.check_expression(inner));
386 CheckType::Known(TypeAnnotation::Result(Box::new(inner_ann)))
387 }
388
389 ExpressionKind::Propagate(inner) => {
390 self.check_expression(inner);
391 CheckType::Unknown
392 }
393
394 ExpressionKind::StructLiteral { name, fields } => {
395 if let Some(declared_fields) = self.records.get(&name).cloned() {
396 for (field_name, value) in &fields {
397 let value_span = self.ast_arena.exprs.get(*value).span;
398 let value_type = self.check_expression(*value);
399 match declared_fields.iter().find(|(n, _)| n == field_name) {
400 Some((_, field_type)) => {
401 let expected = CheckType::Known(field_type.clone());
402 if !value_type.matches(&expected) {
403 self.error(
404 format!(
405 "field `{}` of record `{}` expects {}, got {}",
406 field_name,
407 name,
408 expected.info(),
409 value_type.info()
410 ),
411 value_span,
412 );
413 }
414 }
415 None => {
416 self.error(
417 format!("record `{}` has no field `{}`", name, field_name),
418 value_span,
419 );
420 }
421 }
422 }
423 if fields.len() != declared_fields.len() {
424 self.error(
425 format!(
426 "record `{}` expects {} field(s), got {}",
427 name,
428 declared_fields.len(),
429 fields.len()
430 ),
431 expr_span,
432 );
433 }
434 } else {
435 self.error(format!("unknown record type `{}`", name), expr_span);
436 for (_, value) in &fields {
437 self.check_expression(*value);
438 }
439 }
440 CheckType::Known(TypeAnnotation::Record(name))
441 }
442
443 ExpressionKind::FieldAccess { target, field } => {
444 let target_type = self.check_expression(target);
445 match &target_type {
446 CheckType::Known(
447 TypeAnnotation::Record(name) | TypeAnnotation::CRecord(name),
448 ) => {
449 match self.records.get(name).and_then(|fs| {
450 fs.iter().find(|(n, _)| *n == field).map(|(_, t)| t.clone())
451 }) {
452 Some(field_type) => CheckType::Known(field_type),
453 None => {
454 self.error(
455 format!("record `{}` has no field `{}`", name, field),
456 expr_span,
457 );
458 CheckType::Unknown
459 }
460 }
461 }
462 CheckType::Unknown => CheckType::Unknown,
463 other => {
464 self.error(
465 format!("cannot access field `{}` on {}", field, other.info()),
466 expr_span,
467 );
468 CheckType::Unknown
469 }
470 }
471 }
472
473 ExpressionKind::FieldAssign {
474 target,
475 field,
476 value,
477 } => {
478 let target_type = self.check_expression(target);
479 let value_type = self.check_expression(value);
480 match &target_type {
481 CheckType::Known(
482 TypeAnnotation::Record(name) | TypeAnnotation::CRecord(name),
483 ) => {
484 match self.records.get(name).and_then(|fs| {
485 fs.iter().find(|(n, _)| *n == field).map(|(_, t)| t.clone())
486 }) {
487 Some(field_type) => {
488 let expected = CheckType::Known(field_type);
489 if !value_type.matches(&expected) {
490 self.error(
491 format!(
492 "field `{}` of record `{}` expects {}, got {}",
493 field,
494 name,
495 expected.info(),
496 value_type.info()
497 ),
498 expr_span,
499 );
500 }
501 }
502 None => {
503 self.error(
504 format!("record `{}` has no field `{}`", name, field),
505 expr_span,
506 );
507 }
508 }
509 }
510 CheckType::Unknown => {}
511 other => {
512 self.error(
513 format!("cannot assign field `{}` on {}", field, other.info()),
514 expr_span,
515 );
516 }
517 }
518 value_type
519 }
520
521 ExpressionKind::EnumVariant { enum_name, variant } => {
522 match self.tags.get(&enum_name) {
523 Some(variants) => {
524 if !variants.contains(&variant) {
525 self.error(
526 format!("tag `{}` has no variant `{}`", enum_name, variant),
527 expr_span,
528 );
529 }
530 }
531 None => {
532 self.error(format!("unknown tag type `{}`", enum_name), expr_span);
533 }
534 }
535 CheckType::Known(TypeAnnotation::Enum(enum_name))
536 }
537
538 ExpressionKind::SetLiteral(items) => {
539 let mut item_types = Vec::with_capacity(items.len());
540 for item in items {
541 let item_span = self.ast_arena.exprs.get(item).span;
542 item_types.push((self.check_expression(item), item_span));
543 }
544
545 let items_type = item_types
546 .first()
547 .map(|(t, _)| Self::to_type_annotation(t))
548 .unwrap_or(TypeAnnotation::Null);
549
550 if let Some((first_type, _)) = item_types.first().cloned() {
551 for (item_type, span) in item_types.iter().skip(1) {
552 if !item_type.is_null()
553 && !first_type.is_null()
554 && !item_type.matches(&first_type)
555 {
556 self.error(
557 format!(
558 "set element type mismatch: expected {}, got {}",
559 first_type.info(),
560 item_type.info()
561 ),
562 *span,
563 );
564 }
565 }
566 }
567
568 CheckType::Known(TypeAnnotation::Set(Box::new(items_type)))
569 }
570
571 _ => CheckType::Unknown,
572 }
573 }
574}