diff --git a/editor/src/lang/constrain.rs b/editor/src/lang/constrain.rs index 4745d6970f..d2119581c9 100644 --- a/editor/src/lang/constrain.rs +++ b/editor/src/lang/constrain.rs @@ -21,7 +21,7 @@ use roc_types::{ pub enum Constraint<'a> { Eq(Type2, Expected, Category, Region), // Store(Type, Variable, &'static str, u32), - // Lookup(Symbol, Expected, Region), + Lookup(Symbol, Expected, Region), // Pattern(Region, PatternCategory, Type, PExpected), And(BumpVec<'a, Constraint<'a>>), Let(&'a LetConstraint<'a>), @@ -52,6 +52,7 @@ pub fn constrain_expr<'a>( Expr2::SmallStr(_) => Eq(str_type(env.pool), expected, Category::Str, region), Expr2::Blank => True, Expr2::EmptyRecord => constrain_empty_record(expected, region), + Expr2::Var(symbol) => Lookup(*symbol, expected, region), Expr2::SmallInt { var, .. } => { let mut flex_vars = BumpVec::with_capacity_in(1, arena); diff --git a/editor/src/lang/solve.rs b/editor/src/lang/solve.rs index b50b9d4300..fa5e0473a7 100644 --- a/editor/src/lang/solve.rs +++ b/editor/src/lang/solve.rs @@ -1,7 +1,7 @@ #![allow(clippy::all)] #![allow(dead_code)] use crate::lang::constrain::Constraint::{self, *}; -use crate::lang::pool::Pool; +use crate::lang::pool::{Pool, ShallowClone}; use crate::lang::types::Type2; use bumpalo::Bump; use roc_can::expected::{Expected, PExpected}; @@ -270,75 +270,79 @@ fn solve<'a>( // } // } // } - // Lookup(symbol, expectation, region) => { - // match env.vars_by_symbol.get(&symbol) { - // Some(var) => { - // // Deep copy the vars associated with this symbol before unifying them. - // // Otherwise, suppose we have this: - // // - // // identity = \a -> a - // // - // // x = identity 5 - // // - // // When we call (identity 5), it's important that we not unify - // // on identity's original vars. If we do, the type of `identity` will be - // // mutated to be `Int -> Int` instead of `a -> `, which would be incorrect; - // // the type of `identity` is more general than that! - // // - // // Instead, we want to unify on a *copy* of its vars. If the copy unifies - // // successfully (in this case, to `Int -> Int`), we can use that to - // // infer the type of this lookup (in this case, `Int`) without ever - // // having mutated the original. - // // - // // If this Lookup is targeting a value in another module, - // // then we copy from that module's Subs into our own. If the value - // // is being looked up in this module, then we use our Subs as both - // // the source and destination. - // let actual = deep_copy_var(subs, rank, pools, *var); - // let expected = type_to_var( - // subs, - // rank, - // pools, - // cached_aliases, - // expectation.get_type_ref(), - // ); - // match unify(subs, actual, expected) { - // Success(vars) => { - // introduce(subs, rank, pools, &vars); - // - // state - // } - // - // Failure(vars, actual_type, expected_type) => { - // introduce(subs, rank, pools, &vars); - // - // let problem = TypeError::BadExpr( - // *region, - // Category::Lookup(*symbol), - // actual_type, - // expectation.clone().replace(expected_type), - // ); - // - // problems.push(problem); - // - // state - // } - // BadType(vars, problem) => { - // introduce(subs, rank, pools, &vars); - // - // problems.push(TypeError::BadType(problem)); - // - // state - // } - // } - // } - // None => { - // problems.push(TypeError::UnexposedLookup(*symbol)); - // - // state - // } - // } - // } + Lookup(symbol, expectation, region) => { + match env.vars_by_symbol.get(&symbol) { + Some(var) => { + // Deep copy the vars associated with this symbol before unifying them. + // Otherwise, suppose we have this: + // + // identity = \a -> a + // + // x = identity 5 + // + // When we call (identity 5), it's important that we not unify + // on identity's original vars. If we do, the type of `identity` will be + // mutated to be `Int -> Int` instead of `a -> `, which would be incorrect; + // the type of `identity` is more general than that! + // + // Instead, we want to unify on a *copy* of its vars. If the copy unifies + // successfully (in this case, to `Int -> Int`), we can use that to + // infer the type of this lookup (in this case, `Int`) without ever + // having mutated the original. + // + // If this Lookup is targeting a value in another module, + // then we copy from that module's Subs into our own. If the value + // is being looked up in this module, then we use our Subs as both + // the source and destination. + let actual = deep_copy_var(subs, rank, pools, *var); + + let expected = type_to_var( + arena, + mempool, + subs, + rank, + pools, + cached_aliases, + expectation.get_type_ref(), + ); + + match unify(subs, actual, expected) { + Success(vars) => { + introduce(subs, rank, pools, &vars); + + state + } + + Failure(vars, actual_type, expected_type) => { + introduce(subs, rank, pools, &vars); + + let problem = TypeError::BadExpr( + *region, + Category::Lookup(*symbol), + actual_type, + expectation.shallow_clone().replace(expected_type), + ); + + problems.push(problem); + + state + } + BadType(vars, problem) => { + introduce(subs, rank, pools, &vars); + + problems.push(TypeError::BadType(problem)); + + state + } + } + } + None => { + problems.push(TypeError::UnexposedLookup(*symbol)); + + state + } + } + } And(sub_constraints) => { let mut state = state;