core: Add report_type_error to enable more code reuse

This commit is contained in:
David Mak 2024-07-09 13:43:57 +08:00
parent c820daf5f8
commit bc40a32524

View File

@ -4,13 +4,12 @@ use std::iter::once;
use std::ops::Not; use std::ops::Not;
use std::{cell::RefCell, sync::Arc}; use std::{cell::RefCell, sync::Arc};
use super::typedef::OperatorInfo;
use super::{ use super::{
magic_methods::*, magic_methods::*,
type_error::TypeError, type_error::{TypeError, TypeErrorKind},
typedef::{ typedef::{
into_var_map, iter_type_vars, Call, CallId, FunSignature, FuncArg, RecordField, Type, into_var_map, iter_type_vars, Call, CallId, FunSignature, FuncArg, OperatorInfo,
TypeEnum, TypeVar, Unifier, VarMap, RecordField, RecordKey, Type, TypeEnum, TypeVar, Unifier, VarMap,
}, },
}; };
use crate::{ use crate::{
@ -114,6 +113,14 @@ fn report_error<T>(msg: &str, location: Location) -> Result<T, HashSet<String>>
Err(HashSet::from([format!("{msg} at {location}")])) Err(HashSet::from([format!("{msg} at {location}")]))
} }
fn report_type_error<T>(
kind: TypeErrorKind,
loc: Option<Location>,
unifier: &Unifier,
) -> Result<T, HashSet<String>> {
Err(HashSet::from([TypeError::new(kind, loc).to_display(unifier).to_string()]))
}
impl<'a> Fold<()> for Inferencer<'a> { impl<'a> Fold<()> for Inferencer<'a> {
type TargetU = Option<Type>; type TargetU = Option<Type>;
type Error = HashSet<String>; type Error = HashSet<String>;
@ -1659,9 +1666,11 @@ impl<'a> Inferencer<'a> {
// just a fast path // just a fast path
match (fields.get(&attr), ctx == ExprContext::Store) { match (fields.get(&attr), ctx == ExprContext::Store) {
(Some((ty, true)), _) | (Some((ty, false)), false) => Ok(*ty), (Some((ty, true)), _) | (Some((ty, false)), false) => Ok(*ty),
(Some((_, false)), true) => { (Some((ty, false)), true) => report_type_error(
report_error(&format!("Field `{attr}` is immutable"), value.location) TypeErrorKind::MutationError(RecordKey::Str(attr), *ty),
} Some(value.location),
self.unifier,
),
(None, mutable) => { (None, mutable) => {
// Check whether it is a class attribute // Check whether it is a class attribute
let defs = self.top_level.definitions.read(); let defs = self.top_level.definitions.read();
@ -1683,13 +1692,11 @@ impl<'a> Inferencer<'a> {
&format!("Class Attribute `{attr}` is immutable"), &format!("Class Attribute `{attr}` is immutable"),
value.location, value.location,
), ),
None => { None => report_type_error(
let t = self.unifier.stringify(ty); TypeErrorKind::NoSuchField(RecordKey::Str(attr), ty),
report_error( Some(value.location),
&format!("`{t}::{attr}` field/method does not exist"), self.unifier,
value.location, ),
)
}
} }
} }
} }