feat: allow assignments to be cast to other types

This commit is contained in:
rvcas 2022-11-23 19:05:54 -05:00 committed by Lucas
parent 34d7a28351
commit c07b9a1a81
2 changed files with 43 additions and 24 deletions

View File

@ -771,20 +771,36 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
location: Span, location: Span,
) -> Result<TypedExpr, Error> { ) -> Result<TypedExpr, Error> {
let value = self.in_new_scope(|value_typer| value_typer.infer(value))?; let value = self.in_new_scope(|value_typer| value_typer.infer(value))?;
let value_typ = value.tipo(); let mut value_typ = value.tipo();
// Ensure the pattern matches the type of the value
let pattern = PatternTyper::new(self.environment, &self.hydrator)
.unify(pattern, value_typ.clone())?;
// Check that any type annotation is accurate. // Check that any type annotation is accurate.
if let Some(ann) = annotation { let pattern = if let Some(ann) = annotation {
let ann_typ = self let ann_typ = self
.type_from_annotation(ann) .type_from_annotation(ann)
.map(|t| self.instantiate(t, &mut HashMap::new()))?; .map(|t| self.instantiate(t, &mut HashMap::new()))?;
self.unify(ann_typ, value_typ.clone(), value.type_defining_location())?; self.unify(
} ann_typ.clone(),
value_typ.clone(),
value.type_defining_location(),
)?;
value_typ = ann_typ.clone();
// Ensure the pattern matches the type of the value
PatternTyper::new(self.environment, &self.hydrator).unify(
pattern,
value_typ.clone(),
Some(ann_typ),
)?
} else {
// Ensure the pattern matches the type of the value
PatternTyper::new(self.environment, &self.hydrator).unify(
pattern,
value_typ.clone(),
None,
)?
};
// We currently only do limited exhaustiveness checking of custom types // We currently only do limited exhaustiveness checking of custom types
// at the top level of patterns. // at the top level of patterns.
@ -1688,8 +1704,11 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
}; };
// Ensure the pattern matches the type of the value // Ensure the pattern matches the type of the value
let pattern = PatternTyper::new(self.environment, &self.hydrator) let pattern = PatternTyper::new(self.environment, &self.hydrator).unify(
.unify(pattern, value_type.clone())?; pattern,
value_type.clone(),
None,
)?;
// Check the type of the following code // Check the type of the following code
let then = self.infer(then)?; let then = self.infer(then)?;

View File

@ -144,7 +144,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
// Unify each pattern in the multi-pattern with the corresponding subject // Unify each pattern in the multi-pattern with the corresponding subject
let mut typed_multi = Vec::with_capacity(multi_pattern.len()); let mut typed_multi = Vec::with_capacity(multi_pattern.len());
for (pattern, subject_type) in multi_pattern.into_iter().zip(subjects) { for (pattern, subject_type) in multi_pattern.into_iter().zip(subjects) {
let pattern = self.unify(pattern, subject_type.clone())?; let pattern = self.unify(pattern, subject_type.clone(), None)?;
typed_multi.push(pattern); typed_multi.push(pattern);
} }
Ok(typed_multi) Ok(typed_multi)
@ -224,12 +224,13 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
&mut self, &mut self,
pattern: UntypedPattern, pattern: UntypedPattern,
tipo: Arc<Type>, tipo: Arc<Type>,
ann_type: Option<Arc<Type>>,
) -> Result<TypedPattern, Error> { ) -> Result<TypedPattern, Error> {
match pattern { match pattern {
Pattern::Discard { name, location } => Ok(Pattern::Discard { name, location }), Pattern::Discard { name, location } => Ok(Pattern::Discard { name, location }),
Pattern::Var { name, location, .. } => { Pattern::Var { name, location } => {
self.insert_variable(&name, tipo, location, location)?; self.insert_variable(&name, ann_type.unwrap_or(tipo), location, location)?;
Ok(Pattern::Var { name, location }) Ok(Pattern::Var { name, location })
} }
@ -288,9 +289,14 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
pattern, pattern,
location, location,
} => { } => {
self.insert_variable(&name, tipo.clone(), location, pattern.location())?; self.insert_variable(
&name,
ann_type.clone().unwrap_or_else(|| tipo.clone()),
location,
pattern.location(),
)?;
let pattern = self.unify(*pattern, tipo)?; let pattern = self.unify(*pattern, tipo, ann_type)?;
Ok(Pattern::Assign { Ok(Pattern::Assign {
name, name,
@ -324,11 +330,11 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
let elements = elements let elements = elements
.into_iter() .into_iter()
.map(|element| self.unify(element, tipo.clone())) .map(|element| self.unify(element, tipo.clone(), None))
.try_collect()?; .try_collect()?;
let tail = match tail { let tail = match tail {
Some(tail) => Some(Box::new(self.unify(*tail, list(tipo))?)), Some(tail) => Some(Box::new(self.unify(*tail, list(tipo), None)?)),
None => None, None => None,
}; };
@ -397,12 +403,6 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
// }) // })
// } // }
// }, // },
// Pattern::BitString { location, segments } => {
// self.environment
// .unify(type_, bit_string())
// .map_err(|e| convert_unify_error(e, location))?;
// self.infer_pattern_bit_string(segments, location)
// }
Pattern::Constructor { Pattern::Constructor {
location, location,
module, module,
@ -506,7 +506,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
label, label,
} = arg; } = arg;
let value = self.unify(value, typ.clone())?; let value = self.unify(value, typ.clone(), None)?;
Ok(CallArg { Ok(CallArg {
value, value,