Infer interpolated strings

This commit is contained in:
Richard Feldman 2019-08-30 00:57:18 -04:00
parent 429e7cd26d
commit eae1f564db
4 changed files with 34 additions and 16 deletions

View file

@ -23,7 +23,7 @@ pub enum Expr {
// Lookups // Lookups
Var(Symbol), Var(Symbol),
InterpolatedStr(Vec<(String, Expr)>, String), InterpolatedStr(Vec<(String, Located<Expr>)>, String),
// Pattern Matching // Pattern Matching
Case(Box<Located<Expr>>, Vec<(Located<Pattern>, Located<Expr>)>), Case(Box<Located<Expr>>, Vec<(Located<Pattern>, Located<Expr>)>),
@ -431,7 +431,7 @@ fn canonicalize(
expr::Expr::InterpolatedStr(pairs, suffix) => { expr::Expr::InterpolatedStr(pairs, suffix) => {
let mut output = Output::new(); let mut output = Output::new();
let can_pairs: Vec<(String, Expr)> = pairs.into_iter().map(|(string, loc_ident)| { let can_pairs: Vec<(String, Located<Expr>)> = pairs.into_iter().map(|(string, loc_ident)| {
// From a language design perspective, we only permit idents in interpolation. // From a language design perspective, we only permit idents in interpolation.
// However, in a canonical Expr we store it as a full Expr, not a Symbol. // However, in a canonical Expr we store it as a full Expr, not a Symbol.
// This is so that we can resolve it to either Var or Unrecognized; if we // This is so that we can resolve it to either Var or Unrecognized; if we
@ -440,7 +440,7 @@ fn canonicalize(
match resolve_ident(&env, &scope, loc_ident.value, &mut output.references) { match resolve_ident(&env, &scope, loc_ident.value, &mut output.references) {
Ok(symbol) => Var(symbol), Ok(symbol) => Var(symbol),
Err(ident) => { Err(ident) => {
let loc_ident = Located {region: loc_ident.region, value: ident}; let loc_ident = Located {region: loc_ident.region.clone(), value: ident};
env.problem(Problem::UnrecognizedConstant(loc_ident.clone())); env.problem(Problem::UnrecognizedConstant(loc_ident.clone()));
@ -448,7 +448,7 @@ fn canonicalize(
} }
}; };
(string, can_expr) (string, Located { region: loc_ident.region, value: can_expr })
}).collect(); }).collect();
(InterpolatedStr(can_pairs, suffix), output) (InterpolatedStr(can_pairs, suffix), output)

View file

@ -32,7 +32,20 @@ pub fn constrain(
Approx(_) => { fractional(subs, expected, region) }, Approx(_) => { fractional(subs, expected, region) },
Str(_) => { Eq(string(), expected, region) }, Str(_) => { Eq(string(), expected, region) },
EmptyStr => { Eq(string(), expected, region) }, EmptyStr => { Eq(string(), expected, region) },
InterpolatedStr(_, _) => { Eq(string(), expected, region) }, InterpolatedStr(pairs, _) => {
let mut constraints = Vec::with_capacity(pairs.len() + 1);
for (_, loc_interpolated_expr) in pairs {
let expected_str = ForReason(Reason::InterpolatedStringVar, string(), loc_interpolated_expr.region.clone());
let constraint = constrain(bound_vars, subs, loc_interpolated_expr, expected_str);
constraints.push(constraint);
}
constraints.push(Eq(string(), expected, region));
And(constraints)
},
EmptyRecord => { Eq(EmptyRec, expected, region) }, EmptyRecord => { Eq(EmptyRec, expected, region) },
EmptyList => { Eq(empty_list(subs.mk_flex_var()), expected, region) }, EmptyList => { Eq(empty_list(subs.mk_flex_var()), expected, region) },
List(elems) => { list(elems, bound_vars, subs, expected, region) }, List(elems) => { list(elems, bound_vars, subs, expected, region) },

View file

@ -39,6 +39,7 @@ pub enum Reason {
OperatorLeftArg(Operator), OperatorLeftArg(Operator),
OperatorRightArg(Operator), OperatorRightArg(Operator),
FractionalLiteral, FractionalLiteral,
InterpolatedStringVar,
ElemInList, ElemInList,
} }

View file

@ -216,6 +216,21 @@ mod test_infer {
); );
} }
// INTERPOLATED STRING
#[test]
fn infer_interpolated_string() {
infer_eq(
indoc!(r#"
whatItIs = "great"
"type inference is \(whatItIs)!"
"#),
"String.String"
);
}
// LIST MISMATCH // LIST MISMATCH
#[test] #[test]
@ -343,17 +358,6 @@ mod test_infer {
} }
// #[test]
// fn infer_interpolated_string() {
// infer_eq(
// indoc!(r#"
// whatItIs = "great"
// "type inference is \(whatItIs)!"
// "#),
// "String.String"
// );
// }
// #[test] // #[test]
// fn int_thunk() { // fn int_thunk() {