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;
}
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 {
}
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);
}
}
}
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;
}
}
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);
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");
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 \
--- /dev/null
+Invalid Code
+
+[Compact (opaque = true)]
+class Foo {
+ public abstract void bar ();
+}
+
+void main () {
+}
--- /dev/null
+Invalid Code
+
+[Compact (opaque = true)]
+class Foo {
+ public abstract int bar { get; set; }
+}
+
+void main () {
+}
--- /dev/null
+[Compact (opaque = true)]
+public class Foo {
+ public int bar { get; set; }
+}
+
+void main () {
+ var foo = new Foo ();
+ foo.bar = 42;
+ assert (foo.bar == 42);
+}
--- /dev/null
+Invalid Code
+
+[Compact (opaque = true)]
+class Foo {
+ public int i;
+}
+
+void main () {
+}
--- /dev/null
+[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);
+}
}
}
+ /**
+ * 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.
*/
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;
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) {
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)) {
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) {
"Immutable", "",
"SingleInstance", "",
- "Compact", "",
+ "Compact", "opaque", "",
"NoWrapper", "",
"NoThrow", "",
"DestroysInstance", "",