summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRico Tzschichholz <ricotz@ubuntu.com>2023-04-27 23:37:13 +0200
committerRico Tzschichholz <ricotz@ubuntu.com>2023-04-27 23:47:54 +0200
commit26df498981c893812ff05794360d38d4a37146a4 (patch)
tree8e3e89e297ad3aa4f7db0271a844e11091950aad
parent999c89f4e1f4997343c08b0236899a7872e83faf (diff)
downloadvala-wip/generics-constraints.tar.gz
WIP Handle extended syntaxwip/generics-constraints
-rw-r--r--vala/valacodewriter.vala6
-rw-r--r--vala/valadatatype.vala32
-rw-r--r--vala/valagenerictype.vala10
-rw-r--r--vala/valamethodcall.vala4
-rw-r--r--vala/valaparser.vala4
-rw-r--r--vala/valatypeparameter.vala93
6 files changed, 99 insertions, 50 deletions
diff --git a/vala/valacodewriter.vala b/vala/valacodewriter.vala
index c587a559a..6491c860a 100644
--- a/vala/valacodewriter.vala
+++ b/vala/valacodewriter.vala
@@ -1787,16 +1787,14 @@ public class Vala.CodeWriter : CodeVisitor {
void write_type_parameter_constraints (List<TypeParameter> type_params) {
if (type_params.size > 0) {
foreach (TypeParameter type_param in type_params) {
- unowned DataType? type_constraint = type_param.type_constraint;
- if (type_constraint == null) {
+ if (!type_param.has_type_constraints ()) {
continue;
}
write_string (" where ");
write_identifier (type_param.name);
write_string (" : ");
bool first = true;
- //FIXME
- foreach (DataType type in new DataType[] { type_constraint }) {
+ foreach (DataType type in type_param.get_type_constraints ()) {
if (first) {
first = false;
} else {
diff --git a/vala/valadatatype.vala b/vala/valadatatype.vala
index 1f57ea4a2..ec4fdbd6c 100644
--- a/vala/valadatatype.vala
+++ b/vala/valadatatype.vala
@@ -319,9 +319,10 @@ public abstract class Vala.DataType : CodeNode {
/* temporarily ignore type parameters */
if (target_type is GenericType) {
- unowned DataType? constraint_type = ((GenericType) target_type).type_parameter.type_constraint;
- if (constraint_type != null) {
- return compatible (constraint_type);
+ foreach (DataType type_constraint in ((GenericType) target_type).type_parameter.get_type_constraints ()) {
+ if (!compatible (type_constraint)) {
+ return false;
+ }
}
return true;
}
@@ -567,7 +568,7 @@ public abstract class Vala.DataType : CodeNode {
}
}
- return get_constrained_type (type_param);
+ return type_param.get_constrained_type ();
}
/**
@@ -699,7 +700,7 @@ public abstract class Vala.DataType : CodeNode {
var type_params = ((GenericSymbol) type_symbol).get_type_parameters ();
bool mitigated = true;
foreach (var t in type_params) {
- var ct = get_constrained_type (t);
+ var ct = t.get_constrained_type ();
if (ct != null) {
Report.notice (source_reference, "`%s' requires type arguments, constraining `%s' to `%s'", type_symbol.to_string (), t.name, ct.to_qualified_string ());
add_type_argument (ct);
@@ -725,23 +726,16 @@ public abstract class Vala.DataType : CodeNode {
}
it.next ();
- unowned DataType? constraint_type = it.get ().type_constraint;
- if (constraint_type != null && !type.compatible (constraint_type)) {
- error = true;
- Report.error (type.source_reference, "Cannot convert from `%s' to `%s'", type.to_string (), constraint_type.to_string ());
- return false;
+ unowned List<DataType> type_constraints = it.get ().get_type_constraints ();
+ foreach (DataType type_constraint in type_constraints) {
+ if (!type.compatible (type_constraint)) {
+ error = true;
+ Report.error (type.source_reference, "Cannot convert from `%s' to `%s'", type.to_string (), type_constraint.to_string ());
+ return false;
+ }
}
}
return true;
}
-
- DataType? get_constrained_type (TypeParameter type_param) {
- unowned DataType? type = type_param.type_constraint;
- if (type != null) {
- return type.copy ();
- }
-
- return null;
- }
}
diff --git a/vala/valagenerictype.vala b/vala/valagenerictype.vala
index 3a81449c1..c4e770fbd 100644
--- a/vala/valagenerictype.vala
+++ b/vala/valagenerictype.vala
@@ -53,9 +53,13 @@ public class Vala.GenericType : DataType {
}
public override bool compatible (DataType target_type) {
- unowned DataType? constraint_type = type_parameter.type_constraint;
- if (constraint_type != null) {
- return constraint_type.compatible (target_type);
+ if (type_parameter.has_type_constraints ()) {
+ foreach (DataType type_constraint in type_parameter.get_type_constraints ()) {
+ if (!type_constraint.compatible (target_type)) {
+ return false;
+ }
+ }
+ return true;
}
return base.compatible (target_type);
diff --git a/vala/valamethodcall.vala b/vala/valamethodcall.vala
index 979b845a2..c32230c35 100644
--- a/vala/valamethodcall.vala
+++ b/vala/valamethodcall.vala
@@ -598,10 +598,10 @@ public class Vala.MethodCall : Expression, CallableExpression {
type_arg = m.return_type.infer_type_argument (type_param, target_type);
}
- unowned DataType? ct = type_param.type_constraint;
+ DataType? ct = type_param.get_constrained_type ();
if (ct != null) {
Report.notice (source_reference, "`%s' requires type arguments, constraining `%s' to `%s'", m.to_string (), type_param.name, ct.to_qualified_string ());
- type_arg = ct.copy ();
+ type_arg = ct;
}
if (type_arg == null) {
diff --git a/vala/valaparser.vala b/vala/valaparser.vala
index 197b2d0da..672d1729d 100644
--- a/vala/valaparser.vala
+++ b/vala/valaparser.vala
@@ -4045,12 +4045,12 @@ public class Vala.Parser : CodeVisitor {
do {
/*
where T : <base class name>
- where T : <interface name>
+ where T : <interface name>[, <interface name>]
where T : U
*/
begin = get_location ();
var type = parse_type (true, false);
- type_param.type_constraint = type;
+ type_param.add_type_constraint (type);
} while (accept (TokenType.COMMA));
}
}
diff --git a/vala/valatypeparameter.vala b/vala/valatypeparameter.vala
index 64bd048d8..dd96dcd50 100644
--- a/vala/valatypeparameter.vala
+++ b/vala/valatypeparameter.vala
@@ -26,22 +26,8 @@ using GLib;
* Represents a generic type parameter in the source code.
*/
public class Vala.TypeParameter : TypeSymbol {
- public DataType? type_constraint {
- get {
- if (_type_constraint is GenericType) {
- return ((GenericType) _type_constraint).type_parameter.type_constraint;
- }
- return _type_constraint;
- }
- set {
- _type_constraint = value;
- if (_type_constraint != null) {
- _type_constraint.parent_node = this;
- }
- }
- }
-
- DataType? _type_constraint;
+ List<DataType> type_constraint_list;
+ static List<DataType> _empty_type_list;
/**
* Creates a new generic type parameter.
@@ -55,19 +41,86 @@ public class Vala.TypeParameter : TypeSymbol {
access = SymbolAccessibility.PUBLIC;
}
+ /**
+ * Appends the specified type as generic type constraint.
+ *
+ * @param arg a type reference
+ */
+ public void add_type_constraint (DataType arg) {
+ if (type_constraint_list == null) {
+ type_constraint_list = new ArrayList<DataType> ();
+ }
+ type_constraint_list.add (arg);
+ arg.parent_node = this;
+ }
+
+ /**
+ * Returns the list of generic type constraints.
+ *
+ * @return type constraint list
+ */
+ public unowned List<DataType> get_type_constraints () {
+ if (type_constraint_list != null) {
+ if (type_constraint_list.size > 0 && type_constraint_list[0] is GenericType) {
+ return ((GenericType) type_constraint_list[0]).type_parameter.get_type_constraints ();
+ }
+ return type_constraint_list;
+ }
+ if (_empty_type_list == null) {
+ _empty_type_list = new ArrayList<DataType> ();
+ }
+ return _empty_type_list;
+ }
+
+ public bool has_type_constraints () {
+ if (type_constraint_list == null) {
+ return false;
+ }
+
+ return type_constraint_list.size > 0;
+ }
+
+ public DataType? get_constrained_type () {
+ if (!has_type_constraints ()) {
+ return null;
+ }
+
+ unowned List<DataType> type_constraints = get_type_constraints ();
+ if (type_constraints.size == 1) {
+ return type_constraints[0].copy ();
+ }
+ foreach (DataType type_constraint in type_constraints) {
+ if (type_constraint is ClassType) {
+ return type_constraint.copy ();
+ } else if (type_constraint is InterfaceType) {
+ //FIXME Represent all given interfaces
+ return type_constraint.copy ();
+ }
+ }
+
+ return null;
+ }
+
public override void accept (CodeVisitor visitor) {
visitor.visit_type_parameter (this);
}
public override void accept_children (CodeVisitor visitor) {
- if (_type_constraint != null) {
- _type_constraint.accept (visitor);
+ if (type_constraint_list != null && type_constraint_list.size > 0) {
+ foreach (DataType type_constraint in type_constraint_list) {
+ type_constraint.accept (visitor);
+ }
}
}
public override void replace_type (DataType old_type, DataType new_type) {
- if (_type_constraint == old_type) {
- type_constraint = new_type;
+ if (type_constraint_list != null) {
+ for (int i = 0; i < type_constraint_list.size; i++) {
+ if (type_constraint_list[i] == old_type) {
+ type_constraint_list[i] = new_type;
+ return;
+ }
+ }
}
}