[vala/staging] Add support for 'opaque' compact classes
- From: Rico Tzschichholz <ricotz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala/staging] Add support for 'opaque' compact classes
- Date: Tue, 19 Jan 2021 15:10:24 +0000 (UTC)
commit 19ed5651a3f4a573934d58120be056b62102f554
Author: Simon Werbeck <simon werbeck gmail com>
Date: Thu Mar 19 15:20:39 2020 +0100
Add support for 'opaque' compact classes
This change intruduces a new attribute switch [Compact (opaque = true)]
which allows to completely hide the implementation of a compact class.
This is especially useful for libraries when maintaining a stable abi.
An 'opaque' compact class exposes no struct definition in the generated
c header, only a typedef is provided. As such, certain requirements
apply for members of such classes:
- Access to instance fields must be either private or internal.
- No abstract/virtual methods or properties are allowed.
Fixes https://gitlab.gnome.org/GNOME/vala/issues/1129
codegen/valaccodebasemodule.vala | 2 +-
codegen/valagtypemodule.vala | 17 ++++++++---------
tests/Makefile.am | 5 +++++
tests/semantic/class-opaque-abstract-method.test | 9 +++++++++
tests/semantic/class-opaque-abstract-property.test | 9 +++++++++
.../semantic/class-opaque-automatic-property.vala | 10 ++++++++++
tests/semantic/class-opaque-public-field.test | 9 +++++++++
tests/semantic/class-opaque.vala | 20 ++++++++++++++++++++
vala/valaclass.vala | 22 ++++++++++++++++++++--
vala/valamethod.vala | 5 +++++
vala/valaproperty.vala | 5 +++++
vala/valausedattr.vala | 2 +-
12 files changed, 102 insertions(+), 13 deletions(-)
---
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index 0be29ed99..d27407667 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -675,7 +675,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
public bool add_symbol_declaration (CCodeFile decl_space, Symbol sym, string name) {
bool in_generated_header = context.header_filename != null
- && (decl_space.file_type != CCodeFileType.PUBLIC_HEADER &&
!sym.is_internal_symbol ());
+ && (decl_space.file_type != CCodeFileType.PUBLIC_HEADER &&
!sym.is_internal_symbol () && !(sym is Class && ((Class) sym).is_opaque));
if (decl_space.add_declaration (name)) {
return true;
}
diff --git a/codegen/valagtypemodule.vala b/codegen/valagtypemodule.vala
index d9fbaba65..ebf1ab6d6 100644
--- a/codegen/valagtypemodule.vala
+++ b/codegen/valagtypemodule.vala
@@ -281,7 +281,7 @@ public class Vala.GTypeModule : GErrorModule {
var prop = (Property) s;
generate_struct_property_declaration (cl, prop, instance_struct,
type_struct, decl_space, ref has_struct_member);
} else if (s is Field) {
- if (s.access != SymbolAccessibility.PRIVATE) {
+ if (s.access != SymbolAccessibility.PRIVATE || cl.is_opaque) {
generate_struct_field_declaration ((Field) s,
instance_struct, type_struct, decl_space, ref has_struct_member);
}
} else {
@@ -308,7 +308,7 @@ public class Vala.GTypeModule : GErrorModule {
}
foreach (Field f in cl.get_fields ()) {
- if (f.access != SymbolAccessibility.PRIVATE) {
+ if (f.access != SymbolAccessibility.PRIVATE || cl.is_opaque) {
generate_struct_field_declaration (f, instance_struct, type_struct,
decl_space, ref has_struct_member);
}
}
@@ -475,7 +475,7 @@ public class Vala.GTypeModule : GErrorModule {
}
void generate_class_private_declaration (Class cl, CCodeFile decl_space) {
- if (decl_space.add_declaration ("%sPrivate".printf (get_ccode_name (cl)))) {
+ if (cl.is_opaque || decl_space.add_declaration ("%sPrivate".printf (get_ccode_name (cl)))) {
return;
}
@@ -623,7 +623,11 @@ public class Vala.GTypeModule : GErrorModule {
}
if (!cl.is_internal_symbol ()) {
- generate_class_struct_declaration (cl, header_file);
+ if (!cl.is_opaque) {
+ generate_class_struct_declaration (cl, header_file);
+ } else {
+ generate_class_declaration (cl, header_file);
+ }
}
if (!cl.is_private_symbol ()) {
generate_class_struct_declaration (cl, internal_header_file);
@@ -2356,11 +2360,6 @@ public class Vala.GTypeModule : GErrorModule {
base_prop = prop.base_interface_property;
}
- if (cl != null && cl.is_compact && (prop.get_accessor == null ||
prop.get_accessor.automatic_body)) {
- Report.error (prop.source_reference, "Properties without accessor bodies are not
supported in compact classes");
- return;
- }
-
if (base_prop.get_attribute ("NoAccessorMethod") == null &&
prop.name == "type" && ((cl != null && !cl.is_compact) || (st != null &&
get_ccode_has_type_id (st)))) {
Report.error (prop.source_reference, "Property 'type' not allowed");
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 9ee73d0e7..6211ba77c 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -871,6 +871,11 @@ TESTS = \
semantic/class-compact-interface.test \
semantic/class-compact-method-baseaccess.test \
semantic/class-compact-property-baseaccess.test \
+ semantic/class-opaque.vala \
+ semantic/class-opaque-public-field.test \
+ semantic/class-opaque-abstract-method.test \
+ semantic/class-opaque-abstract-property.test \
+ semantic/class-opaque-automatic-property.vala \
semantic/class-missing-implement-interface-method.test \
semantic/class-missing-implement-interface-property.test \
semantic/class-missing-implement-interfaces-methods.test \
diff --git a/tests/semantic/class-opaque-abstract-method.test
b/tests/semantic/class-opaque-abstract-method.test
new file mode 100644
index 000000000..78048f05f
--- /dev/null
+++ b/tests/semantic/class-opaque-abstract-method.test
@@ -0,0 +1,9 @@
+Invalid Code
+
+[Compact (opaque = true)]
+class Foo {
+ public abstract void bar ();
+}
+
+void main () {
+}
diff --git a/tests/semantic/class-opaque-abstract-property.test
b/tests/semantic/class-opaque-abstract-property.test
new file mode 100644
index 000000000..7588b5da1
--- /dev/null
+++ b/tests/semantic/class-opaque-abstract-property.test
@@ -0,0 +1,9 @@
+Invalid Code
+
+[Compact (opaque = true)]
+class Foo {
+ public abstract int bar { get; set; }
+}
+
+void main () {
+}
diff --git a/tests/semantic/class-opaque-automatic-property.vala
b/tests/semantic/class-opaque-automatic-property.vala
new file mode 100644
index 000000000..8400a78b5
--- /dev/null
+++ b/tests/semantic/class-opaque-automatic-property.vala
@@ -0,0 +1,10 @@
+[Compact (opaque = true)]
+public class Foo {
+ public int bar { get; set; }
+}
+
+void main () {
+ var foo = new Foo ();
+ foo.bar = 42;
+ assert (foo.bar == 42);
+}
diff --git a/tests/semantic/class-opaque-public-field.test b/tests/semantic/class-opaque-public-field.test
new file mode 100644
index 000000000..11bd88942
--- /dev/null
+++ b/tests/semantic/class-opaque-public-field.test
@@ -0,0 +1,9 @@
+Invalid Code
+
+[Compact (opaque = true)]
+class Foo {
+ public int i;
+}
+
+void main () {
+}
diff --git a/tests/semantic/class-opaque.vala b/tests/semantic/class-opaque.vala
new file mode 100644
index 000000000..02f813822
--- /dev/null
+++ b/tests/semantic/class-opaque.vala
@@ -0,0 +1,20 @@
+[Compact (opaque = true)]
+public class Foo {
+ private int i;
+ internal int j;
+
+ public Foo () {
+ i = 42;
+ }
+
+ public int get_i () {
+ return i;
+ }
+}
+
+void main () {
+ var foo = new Foo ();
+ foo.j = 23;
+ assert (foo.j == 23);
+ assert (foo.get_i () == 42);
+}
diff --git a/vala/valaclass.vala b/vala/valaclass.vala
index 7d59cfaad..da1f81a33 100644
--- a/vala/valaclass.vala
+++ b/vala/valaclass.vala
@@ -65,6 +65,19 @@ public class Vala.Class : ObjectTypeSymbol {
}
}
+ /**
+ * Opaque compact classes hide their memory layout, only allowing private or
+ * internal instance members.
+ */
+ public bool is_opaque {
+ get {
+ if (_is_opaque == null) {
+ _is_opaque = get_attribute_bool ("Compact", "opaque");
+ }
+ return _is_opaque;
+ }
+ }
+
/**
* Instances of immutable classes are immutable after construction.
*/
@@ -112,6 +125,7 @@ public class Vala.Class : ObjectTypeSymbol {
public bool has_class_private_fields { get; private set; }
private bool? _is_compact;
+ private bool? _is_opaque;
private bool? _is_immutable;
private bool? _is_singleton;
@@ -624,8 +638,12 @@ public class Vala.Class : ObjectTypeSymbol {
foreach (Field f in get_fields ()) {
if (is_compact && f.binding != MemberBinding.STATIC) {
//FIXME Should external bindings follow this too?
- if (!external_package && f.access == SymbolAccessibility.PRIVATE) {
- Report.error (source_reference, "private fields are not supported in
compact classes");
+ if (!external_package && !is_opaque && f.access ==
SymbolAccessibility.PRIVATE) {
+ Report.error (f.source_reference, "private fields are only supported
in opaque compact classes, use [Compact (opaque = true)]");
+ error = true;
+ }
+ if (!external_package && is_opaque && (f.access == SymbolAccessibility.PUBLIC
|| f.access == SymbolAccessibility.PROTECTED)) {
+ Report.error (f.source_reference, "fields in opaque compact classes
must be private or internal");
error = true;
}
if (f.binding == MemberBinding.CLASS) {
diff --git a/vala/valamethod.vala b/vala/valamethod.vala
index 5f8dce29a..335bf4224 100644
--- a/vala/valamethod.vala
+++ b/vala/valamethod.vala
@@ -735,6 +735,11 @@ public class Vala.Method : Subroutine, Callable {
Report.error (source_reference, "Abstract and virtual methods may not be
declared in derived compact classes");
return false;
}
+ if (cl.is_opaque) {
+ error = true;
+ Report.error (source_reference, "Abstract and virtual methods may not be
declared in opaque compact classes");
+ return false;
+ }
}
if (is_variadic () && (is_abstract || is_virtual)) {
diff --git a/vala/valaproperty.vala b/vala/valaproperty.vala
index 0a2e437d5..f07f137e0 100644
--- a/vala/valaproperty.vala
+++ b/vala/valaproperty.vala
@@ -424,6 +424,11 @@ public class Vala.Property : Symbol, Lockable {
Report.error (source_reference, "Abstract and virtual properties may not be
declared in derived compact classes");
return false;
}
+ if (cl.is_opaque) {
+ error = true;
+ Report.error (source_reference, "Abstract and virtual properties may not be
declared in opaque compact classes");
+ return false;
+ }
}
if (is_abstract) {
diff --git a/vala/valausedattr.vala b/vala/valausedattr.vala
index ffb142eb0..c00d8e6a2 100644
--- a/vala/valausedattr.vala
+++ b/vala/valausedattr.vala
@@ -44,7 +44,7 @@ public class Vala.UsedAttr : CodeVisitor {
"Immutable", "",
"SingleInstance", "",
- "Compact", "",
+ "Compact", "opaque", "",
"NoWrapper", "",
"NoThrow", "",
"DestroysInstance", "",
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]