diff options
author | Rico Tzschichholz <ricotz@ubuntu.com> | 2023-04-27 23:37:13 +0200 |
---|---|---|
committer | Rico Tzschichholz <ricotz@ubuntu.com> | 2023-04-27 23:47:54 +0200 |
commit | 26df498981c893812ff05794360d38d4a37146a4 (patch) | |
tree | 8e3e89e297ad3aa4f7db0271a844e11091950aad | |
parent | 999c89f4e1f4997343c08b0236899a7872e83faf (diff) | |
download | vala-wip/generics-constraints.tar.gz |
WIP Handle extended syntaxwip/generics-constraints
-rw-r--r-- | vala/valacodewriter.vala | 6 | ||||
-rw-r--r-- | vala/valadatatype.vala | 32 | ||||
-rw-r--r-- | vala/valagenerictype.vala | 10 | ||||
-rw-r--r-- | vala/valamethodcall.vala | 4 | ||||
-rw-r--r-- | vala/valaparser.vala | 4 | ||||
-rw-r--r-- | vala/valatypeparameter.vala | 93 |
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; + } + } } } |