diff --git a/crates/erg_compiler/context/generalize.rs b/crates/erg_compiler/context/generalize.rs index 7adc9ef95..64fc56125 100644 --- a/crates/erg_compiler/context/generalize.rs +++ b/crates/erg_compiler/context/generalize.rs @@ -607,7 +607,7 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> { match res { Ok(ty) => { // TODO: T(:> Nat <: Int) -> T(:> Nat, <: Int) ==> Int -> Nat - // fv.link(&ty); + // Type::FreeVar(fv).destructive_link(&ty); Ok(ty) } Err(errs) => { @@ -842,16 +842,8 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> { .check_trait_impl(&sub_t, &super_t, self.qnames, self.loc)?; } let is_subtype = self.ctx.subtype_of(&sub_t, &super_t); - let sub_t = if DEBUG_MODE { - sub_t - } else { - self.deref_tyvar(sub_t)? - }; - let super_t = if DEBUG_MODE { - super_t - } else { - self.deref_tyvar(super_t)? - }; + let sub_t = self.deref_tyvar(sub_t)?; + let super_t = self.deref_tyvar(super_t)?; if sub_t == super_t { Ok(sub_t) } else if is_subtype { @@ -1396,6 +1388,7 @@ impl Context { Type::Or(l, r) => { let l = self.squash_tyvar(*l); let r = self.squash_tyvar(*r); + // REVIEW: if l.is_unnamed_unbound_var() && r.is_unnamed_unbound_var() { match (self.subtype_of(&l, &r), self.subtype_of(&r, &l)) { (true, true) | (true, false) => { @@ -1409,6 +1402,13 @@ impl Context { } self.union(&l, &r) } + Type::FreeVar(ref fv) if fv.constraint_is_sandwiched() => { + let (sub_t, super_t) = fv.get_subsup().unwrap(); + let sub_t = self.squash_tyvar(sub_t); + let super_t = self.squash_tyvar(super_t); + typ.update_tyvar(sub_t, super_t, None, false); + typ + } other => other, } } diff --git a/crates/erg_compiler/context/mod.rs b/crates/erg_compiler/context/mod.rs index bb1a54299..6c1c08c0b 100644 --- a/crates/erg_compiler/context/mod.rs +++ b/crates/erg_compiler/context/mod.rs @@ -1380,7 +1380,7 @@ impl Context { &self.shared().promises } - pub fn current_caller(&self) -> Option { + pub fn current_control_flow(&self) -> Option { self.higher_order_caller .last() .and_then(|name| ControlKind::try_from(&name[..]).ok()) @@ -1395,11 +1395,13 @@ impl Context { None } - pub fn current_function_ctx(&self) -> Option<&Context> { - if self.kind.is_subr() { + /// Context of the function that actually creates the scope. + /// Control flow function blocks do not create actual scopes. + pub fn current_true_function_ctx(&self) -> Option<&Context> { + if self.kind.is_subr() && self.current_control_flow().is_none() { Some(self) } else if let Some(outer) = self.get_outer() { - outer.current_function_ctx() + outer.current_true_function_ctx() } else { None } diff --git a/crates/erg_compiler/lower.rs b/crates/erg_compiler/lower.rs index 1ce1ced2a..1c37a0405 100644 --- a/crates/erg_compiler/lower.rs +++ b/crates/erg_compiler/lower.rs @@ -951,11 +951,7 @@ impl GenericASTLowerer { if !ident.vi.is_toplevel() && ident.vi.def_namespace() != &self.module.context.name && ident.vi.kind.can_capture() - && self - .module - .context - .current_function_ctx() - .is_some_and(|ctx| ctx.control_kind().is_none()) + && self.module.context.current_true_function_ctx().is_some() { self.module.context.captured_names.push(ident.clone()); } @@ -1178,7 +1174,7 @@ impl GenericASTLowerer { if self .module .context - .current_caller() + .current_control_flow() .map_or(true, |kind| !kind.is_if()) && expect.is_some_and(|subr| !subr.essential_qnames().is_empty()) { diff --git a/tests/should_ok/closure.er b/tests/should_ok/closure.er index 3a3e9bf2e..fb529b6f1 100644 --- a/tests/should_ok/closure.er +++ b/tests/should_ok/closure.er @@ -20,3 +20,20 @@ for! [1], _ => push! "a", "b" assert result == "| a | b |\n" + +{SemVer;} = import "semver" + +Versions! = Class Dict! { Str: Array!(SemVer) } +Versions!. + new() = Versions!::__new__ !{:} + insert!(ref! self, name: Str, version: SemVer) = + if! self::base.get(name) == None: + do!: + self::base.insert! name, ![version] + do!: + if! all(map(v -> v != version, self::base[name])), do!: + self::base[name].push! version + +vs = Versions!.new() +_ = vs.insert! "foo", SemVer.from_str "1.0.0" +_ = vs.insert! "foo", SemVer.from_str "1.0.1"