diff --git a/compiler/can/src/constraint.rs b/compiler/can/src/constraint.rs index a3230495d4..38c16b93f4 100644 --- a/compiler/can/src/constraint.rs +++ b/compiler/can/src/constraint.rs @@ -13,8 +13,7 @@ pub struct Constraints { pub constraints: Vec, pub types: Vec, pub variables: Vec, - pub symbols: Vec, - pub regions: Vec, + pub loc_symbols: Vec<(Symbol, Region)>, pub let_constraints: Vec, pub categories: Vec, pub pattern_categories: Vec, @@ -39,8 +38,7 @@ impl Constraints { let constraints = Vec::new(); let mut types = Vec::new(); let variables = Vec::new(); - let symbols = Vec::new(); - let regions = Vec::new(); + let loc_symbols = Vec::new(); let let_constraints = Vec::new(); let mut categories = Vec::with_capacity(16); let mut pattern_categories = Vec::with_capacity(16); @@ -94,8 +92,7 @@ impl Constraints { constraints, types, variables, - symbols, - regions, + loc_symbols, let_constraints, categories, pattern_categories, @@ -369,28 +366,24 @@ impl Constraints { let it = it.into_iter(); let types_start = self.types.len(); - let symbols_start = self.symbols.len(); - let regions_start = self.regions.len(); + let loc_symbols_start = self.loc_symbols.len(); // because we have an ExactSizeIterator, we can reserve space here let length = it.len(); self.types.reserve(length); - self.symbols.reserve(length); - self.regions.reserve(length); + self.loc_symbols.reserve(length); for (symbol, loc_type) in it { let Loc { region, value } = loc_type; self.types.push(value); - self.symbols.push(symbol); - self.regions.push(region); + self.loc_symbols.push((symbol, region)); } DefTypes { types: Slice::new(types_start as _, length as _), - symbols: Slice::new(symbols_start as _, length as _), - regions: Slice::new(regions_start as _, length as _), + loc_symbols: Slice::new(loc_symbols_start as _, length as _), } } @@ -657,24 +650,25 @@ impl Constraints { Constraint::Exhaustive(equality, sketched_rows, context, exhaustive) } - pub fn check_cycle( + pub fn check_cycle( &mut self, - symbols: I, - symbol_regions: I1, - expr_regions: I2, + loc_symbols: I, + expr_regions: I1, cycle_mark: IllegalCycleMark, ) -> Constraint where - I: IntoIterator, + I: IntoIterator, I1: IntoIterator, - I2: IntoIterator, { - let symbols = Slice::extend_new(&mut self.symbols, symbols); - let symbol_regions = Slice::extend_new(&mut self.regions, symbol_regions); - let expr_regions = Slice::extend_new(&mut self.regions, expr_regions); + let def_names = Slice::extend_new(&mut self.loc_symbols, loc_symbols); + + // we add a dummy symbol to these regions, so we can store the data in the loc_symbols vec + let it = expr_regions.into_iter().map(|r| (Symbol::ATTR_ATTR, r)); + let expr_regions = Slice::extend_new(&mut self.loc_symbols, it); + let expr_regions = Slice::new(expr_regions.start() as _, expr_regions.len() as _); + let cycle = Cycle { - symbols, - symbol_regions, + def_names, expr_regions, }; let cycle_index = Index::push_new(&mut self.cycles, cycle); @@ -776,8 +770,7 @@ pub enum Constraint { #[derive(Debug, Clone, Copy, Default)] pub struct DefTypes { pub types: Slice, - pub symbols: Slice, - pub regions: Slice, + pub loc_symbols: Slice<(Symbol, Region)>, } #[derive(Debug, Clone)] @@ -799,8 +792,7 @@ pub struct IncludesTag { #[derive(Debug, Clone, Copy)] pub struct Cycle { - pub symbols: Slice, - pub symbol_regions: Slice, + pub def_names: Slice<(Symbol, Region)>, pub expr_regions: Slice, } diff --git a/compiler/collections/src/soa.rs b/compiler/collections/src/soa.rs index 69e6abb830..bb118fff90 100644 --- a/compiler/collections/src/soa.rs +++ b/compiler/collections/src/soa.rs @@ -105,6 +105,10 @@ impl Slice { self.length as _ } + pub const fn start(&self) -> usize { + self.start as _ + } + pub const fn is_empty(&self) -> bool { self.length == 0 } diff --git a/compiler/constrain/src/expr.rs b/compiler/constrain/src/expr.rs index 0289aa9d77..532b9c985c 100644 --- a/compiler/constrain/src/expr.rs +++ b/compiler/constrain/src/expr.rs @@ -2135,7 +2135,7 @@ pub fn rec_defs_help( flex_constraints, ); - let ((symbols, symbol_regions), expr_regions): ((Vec<_>, Vec<_>), Vec<_>) = defs + let (loc_symbols, expr_regions): (Vec<_>, Vec<_>) = defs .iter() .flat_map(|def| { symbols_introduced_from_pattern(&def.loc_pattern) @@ -2143,8 +2143,7 @@ pub fn rec_defs_help( }) .unzip(); - let cycle_constraint = - constraints.check_cycle(symbols, symbol_regions, expr_regions, cycle_mark); + let cycle_constraint = constraints.check_cycle(loc_symbols, expr_regions, cycle_mark); let rigid_constraints = { let mut temp = rigid_info.constraints; diff --git a/compiler/solve/src/solve.rs b/compiler/solve/src/solve.rs index 5022ff1903..374db1b1e8 100644 --- a/compiler/solve/src/solve.rs +++ b/compiler/solve/src/solve.rs @@ -1399,31 +1399,32 @@ fn solve( } CheckCycle(cycle, cycle_mark) => { let Cycle { - symbols, - symbol_regions, + def_names, expr_regions, } = &constraints.cycles[cycle.index()]; - let symbols = &constraints.symbols[symbols.indices()]; - let mut any_is_bad = false; - for symbol in symbols { - // If the type of a symbol is not a function, that's an error. - // Roc is strict, so only functions can be mutually recursive. - let var = env.get_var_by_symbol(symbol).expect("Symbol not solved!"); - any_is_bad = any_is_bad - || !matches!( - subs.get_content_without_compacting(var), - Content::Error | Content::Structure(FlatType::Func(..)) - ); - } + let symbols = &constraints.loc_symbols[def_names.indices()]; + + // If the type of a symbol is not a function, that's an error. + // Roc is strict, so only functions can be mutually recursive. + let any_is_bad = { + use Content::*; + + symbols.iter().any(|(s, _)| { + let var = env.get_var_by_symbol(s).expect("Symbol not solved!"); + let content = subs.get_content_without_compacting(var); + !matches!(content, Error | Structure(FlatType::Func(..))) + }) + }; if any_is_bad { - let symbol_regions = &constraints.regions[symbol_regions.indices()]; - let expr_regions = &constraints.regions[expr_regions.indices()]; + // expr regions are stored in loc_symbols (that turned out to be convenient). + // The symbol is just a dummy, and should not be used + let expr_regions = &constraints.loc_symbols[expr_regions.indices()]; - let cycle = (symbols.iter()) - .zip(symbol_regions.iter()) + let cycle = symbols + .iter() .zip(expr_regions.iter()) - .map(|((&symbol, &symbol_region), &expr_region)| CycleEntry { + .map(|(&(symbol, symbol_region), &(_, expr_region))| CycleEntry { symbol, symbol_region, expr_region, @@ -1634,15 +1635,11 @@ impl LocalDefVarsVec<(Symbol, Loc)> { def_types_slice: roc_can::constraint::DefTypes, ) -> Self { let types_slice = &constraints.types[def_types_slice.types.indices()]; - let symbols_slice = &constraints.symbols[def_types_slice.symbols.indices()]; - let regions_slice = &constraints.regions[def_types_slice.regions.indices()]; + let loc_symbols_slice = &constraints.loc_symbols[def_types_slice.loc_symbols.indices()]; let mut local_def_vars = Self::with_length(types_slice.len()); - for ((&symbol, ®ion), typ) in (symbols_slice.iter()) - .zip(regions_slice.iter()) - .zip(types_slice) - { + for (&(symbol, region), typ) in (loc_symbols_slice.iter()).zip(types_slice) { let var = type_to_var(subs, rank, pools, aliases, typ); local_def_vars.push((symbol, Loc { value: var, region }));