arrays/slice-invalid-start.test \
arrays/slice-invalid-stop.test \
arrays/slice-no-array.test \
+ arrays/transfer-container-field.test \
+ arrays/transfer-container-local.test \
+ arrays/transfer-container-return.test \
chainup/base-arguments.test \
chainup/base-class-invalid.test \
chainup/base-enum-invalid.test \
--- /dev/null
+Invalid Code
+
+class Foo {
+ private (unowned string)[] field;
+
+ public Foo () {
+ field = new string[] { "what" };
+ }
+}
+
+void main () {
+}
--- /dev/null
+Invalid Code
+
+void main () {
+ (unowned string)[] foo = new string[] { "foo" };
+}
--- /dev/null
+Invalid Code
+
+(unowned string)[] return_string_array () {
+ return new string[] { "foo" };
+}
+
+void main () {
+}
return false;
}
+ public override bool transfer_compatible (DataType target_type) {
+ if (!compatible (target_type)) {
+ return false;
+ }
+ if (!(target_type is ArrayType)) {
+ // Allow pointers etc.
+ return true;
+ }
+ if (value_owned && !target_type.value_owned) {
+ return false;
+ }
+
+ ArrayType target_array_type = (ArrayType) target_type;
+ return element_type.transfer_compatible (target_array_type.element_type);
+ }
+
public override bool is_reference_type_or_type_parameter () {
return true;
}
}
if (!(ma.symbol_reference is Property)) {
- if (right.value_type.is_disposable ()) {
- /* rhs transfers ownership of the expression */
- if (!(left.value_type is PointerType) && !left.value_type.value_owned) {
- /* lhs doesn't own the value */
- error = true;
- Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
- }
- } else if (left.value_type.value_owned) {
- /* lhs wants to own the value
- * rhs doesn't transfer the ownership
- * code generator needs to add reference
- * increment calls */
+ if (!right.value_type.transfer_compatible (left.value_type)) {
+ error = true;
+ Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
}
}
}
return false;
}
- if (right.value_type.is_disposable ()) {
- /* rhs transfers ownership of the expression */
-
- DataType element_type;
+ DataType element_type;
- if (ea.container.value_type is ArrayType) {
- unowned ArrayType array_type = (ArrayType) ea.container.value_type;
- element_type = array_type.element_type;
- } else {
- var args = ea.container.value_type.get_type_arguments ();
- assert (args.size == 1);
- element_type = args.get (0);
- }
+ if (ea.container.value_type is ArrayType) {
+ unowned ArrayType array_type = (ArrayType) ea.container.value_type;
+ element_type = array_type.element_type;
+ } else if (ea.container.value_type is PointerType) {
+ unowned PointerType pointer_type = (PointerType) ea.container.value_type;
+ element_type = pointer_type.base_type;
+ } else {
+ var args = ea.container.value_type.get_type_arguments ();
+ assert (args.size == 1);
+ element_type = args.get (0);
+ }
- if (!(element_type is PointerType) && !element_type.value_owned) {
- /* lhs doesn't own the value */
- error = true;
- Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
- return false;
- }
- } else if (left.value_type.value_owned) {
- /* lhs wants to own the value
- * rhs doesn't transfer the ownership
- * code generator needs to add reference
- * increment calls */
+ if (!right.value_type.transfer_compatible (element_type)) {
+ error = true;
+ Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
+ return false;
}
} else {
return true;
return false;
}
+ public virtual bool transfer_compatible (DataType target_type) {
+ // Check if an instance of this type can transfer ownership (if any)
+ // to an instance of the target type.
+ if (!compatible (target_type)) {
+ return false;
+ }
+ if (target_type is PointerType) {
+ return true;
+ }
+ if (is_disposable () && !target_type.value_owned) {
+ return false;
+ }
+ return true;
+ }
+
/**
* Returns whether instances of this type are invokable.
*
return false;
}
- if (initializer.value_type.is_disposable ()) {
- /* rhs transfers ownership of the expression */
- if (!(variable_type is PointerType) && !variable_type.value_owned) {
- /* lhs doesn't own the value */
- error = true;
- Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
- return false;
- }
+ if (!initializer.value_type.transfer_compatible (variable_type)) {
+ error = true;
+ Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
+ return false;
}
if (parent_symbol is Namespace && !initializer.is_constant ()) {
error = true;
Report.error (source_reference, "Foreach: Cannot convert from `%s' to `%s'", element_type.to_string (), type_reference.to_string ());
return false;
- } else if (element_type.is_disposable () && element_type.value_owned && !type_reference.value_owned) {
+ } else if (!element_type.transfer_compatible (type_reference)) {
error = true;
Report.error (source_reference, "Foreach: Invalid assignment from owned expression to unowned variable");
return false;
return false;
}
- if (initializer.value_type.is_disposable ()) {
- /* rhs transfers ownership of the expression */
- if (!(variable_type is PointerType) && !variable_type.value_owned) {
- /* lhs doesn't own the value */
- error = true;
- Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
- return false;
- }
+ if (!initializer.value_type.transfer_compatible (variable_type)) {
+ error = true;
+ Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
+ return false;
}
}
return false;
}
- if (return_expression.value_type.is_disposable () &&
- !context.analyzer.current_return_type.value_owned) {
+ if (!return_expression.value_type.transfer_compatible (context.analyzer.current_return_type)) {
error = true;
Report.error (source_reference, "Return value transfers ownership but method return type hasn't been declared to transfer ownership");
return false;
}
unowned LocalVariable? local = return_expression.symbol_reference as LocalVariable;
- if (local != null && local.variable_type.is_disposable () &&
- !context.analyzer.current_return_type.value_owned) {
+ if (local != null && !local.variable_type.transfer_compatible (context.analyzer.current_return_type)) {
error = true;
Report.error (source_reference, "Local variable with strong reference used as return value and method return type has not been declared to transfer ownership");
return false;
return false;
}
- // weak variables can only be used with weak ref parameters
- if (arg.target_type.is_disposable ()) {
- if (!(arg.value_type is PointerType) && !arg.value_type.value_owned) {
- /* variable doesn't own the value */
- Report.error (arg.source_reference, "Argument %d: Cannot pass unowned ref argument to owned reference parameter", i + 1);
- return false;
- }
+ // unowned variables can only be used with unowned ref parameters
+ if (!arg.target_type.transfer_compatible (arg.value_type)) {
+ /* variable doesn't own the value */
+ Report.error (arg.source_reference, "Argument %d: Cannot pass unowned ref argument to owned reference parameter", i + 1);
+ return false;
}
// owned variables can only be used with owned ref parameters
- if (arg.value_type.is_disposable ()) {
- if (!arg.target_type.value_owned) {
- /* parameter doesn't own the value */
- Report.error (arg.source_reference, "Argument %d: Cannot pass owned ref argument to unowned reference parameter", i + 1);
- return false;
- }
+ if (!arg.value_type.transfer_compatible (arg.target_type)) {
+ /* parameter doesn't own the value */
+ Report.error (arg.source_reference, "Argument %d: Cannot pass owned ref argument to unowned reference parameter", i + 1);
+ return false;
}
} else if (arg_type == 3) {
if (direction != ParameterDirection.OUT) {
return false;
}
- // weak variables can only be used with weak out parameters
- if (arg.target_type.is_disposable ()) {
- if (!(arg.value_type is PointerType) && !arg.value_type.value_owned) {
- /* variable doesn't own the value */
- Report.error (arg.source_reference, "Invalid assignment from owned expression to unowned variable");
- return false;
- }
+ // unowned variables can only be used with unowned out parameters
+ if (!arg.target_type.transfer_compatible (arg.value_type)) {
+ /* variable doesn't own the value */
+ Report.error (arg.source_reference, "Invalid assignment from owned expression to unowned variable");
+ return false;
}
}
}