From de057f50fb3f612c56e3915751480d198133c032 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 30 May 2024 22:35:43 +0200 Subject: [PATCH] Relax rules for capturing self in uni closures Closures of type `uni fn` are now allowed to capture `self` if it's a value type or a module. Changelog: added --- compiler/src/type_check/expressions.rs | 4 +++ .../diagnostics/closure_capture_self.inko | 26 +++++++++++++++++++ types/src/lib.rs | 6 +++++ 3 files changed, 36 insertions(+) create mode 100644 std/fixtures/diagnostics/closure_capture_self.inko diff --git a/compiler/src/type_check/expressions.rs b/compiler/src/type_check/expressions.rs index a0d066fd0..27e551700 100644 --- a/compiler/src/type_check/expressions.rs +++ b/compiler/src/type_check/expressions.rs @@ -4356,6 +4356,10 @@ impl<'a> CheckMethodBody<'a> { scope: &LexicalScope, location: &SourceLocation, ) { + if scope.surrounding_type.is_value_type(self.db()) { + return; + } + if scope.in_closure_in_recover() { self.state .diagnostics diff --git a/std/fixtures/diagnostics/closure_capture_self.inko b/std/fixtures/diagnostics/closure_capture_self.inko new file mode 100644 index 000000000..6fca1f72a --- /dev/null +++ b/std/fixtures/diagnostics/closure_capture_self.inko @@ -0,0 +1,26 @@ +class A { + fn foo { + recover fn { bar } + recover fn { self.bar } + } + + fn bar {} +} + +impl String { + fn foo { + recover fn { bar } + recover fn { self.bar } + } + + fn bar {} +} + +fn example1 { + recover fn { example2 } +} + +fn example2 {} + +# closure_capture_self.inko:3:18 error(invalid-type): closures inside a 'recover' can't capture or use 'self' +# closure_capture_self.inko:4:18 error(invalid-type): closures inside a 'recover' can't capture or use 'self' diff --git a/types/src/lib.rs b/types/src/lib.rs index de9ff3085..f28a8ecec 100644 --- a/types/src/lib.rs +++ b/types/src/lib.rs @@ -4141,6 +4141,12 @@ impl TypeRef { | TypeRef::Uni(TypeId::ClassInstance(ins)) => { ins.instance_of().is_value_type(db) } + // Modules technically aren't values, but this allows certain checks + // for value types (e.g. to see if `self` can be captured) to + // automatically also handle modules. + TypeRef::Owned(TypeId::Module(_)) + | TypeRef::Ref(TypeId::Module(_)) + | TypeRef::Mut(TypeId::Module(_)) => true, TypeRef::Owned(TypeId::Foreign(_)) => true, TypeRef::Pointer(_) => true, TypeRef::Placeholder(id) => {