Browse Source

Implement Allow `.?` operator to unwrap any union #549

gingerBill 5 years ago
parent
commit
af1d4d6e72
2 changed files with 21 additions and 2 deletions
  1. 20 1
      src/check_expr.cpp
  2. 1 1
      src/parser.hpp

+ 20 - 1
src/check_expr.cpp

@@ -8897,12 +8897,31 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
 		if (ta->type != nullptr && ta->type->kind == Ast_UnaryExpr && ta->type->UnaryExpr.op.kind == Token_Question) {
 			if (!is_type_union(src)) {
 				gbString str = type_to_string(o->type);
-				error(o->expr, "Type assertions with .? can only operate on unions with 1 variant, got %s", str);
+				error(o->expr, "Type assertions with .? can only operate on unions, got %s", str);
 				gb_string_free(str);
 				o->mode = Addressing_Invalid;
 				o->expr = node;
 				return kind;
 			}
+
+			if (bsrc->Union.variants.count != 1 && type_hint != nullptr) {
+				bool allowed = false;
+				for_array(i, bsrc->Union.variants) {
+					Type *vt = bsrc->Union.variants[i];
+					if (are_types_identical(vt, type_hint)) {
+						allowed = true;
+						add_type_info_type(c, vt);
+						break;
+					}
+				}
+				if (allowed) {
+					add_type_info_type(c, o->type);
+					o->type = type_hint;
+					o->mode = Addressing_OptionalOk;
+					return kind;
+				}
+			}
+
 			if (bsrc->Union.variants.count != 1) {
 				error(o->expr, "Type assertions with .? can only operate on unions with 1 variant, got %lld", cast(long long)bsrc->Union.variants.count);
 				o->mode = Addressing_Invalid;

+ 1 - 1
src/parser.hpp

@@ -292,7 +292,7 @@ AST_KIND(_ExprBegin,  "",  bool) \
 	AST_KIND(TernaryExpr,     "ternary expression",       struct { Ast *cond, *x, *y; }) \
 	AST_KIND(TernaryIfExpr,   "ternary if expression",    struct { Ast *x, *cond, *y; }) \
 	AST_KIND(TernaryWhenExpr, "ternary when expression",  struct { Ast *x, *cond, *y; }) \
-	AST_KIND(TypeAssertion, "type assertion",      struct { Ast *expr; Token dot; Ast *type; }) \
+	AST_KIND(TypeAssertion, "type assertion",      struct { Ast *expr; Token dot; Ast *type; Type *type_hint; }) \
 	AST_KIND(TypeCast,      "type cast",           struct { Token token; Ast *type, *expr; }) \
 	AST_KIND(AutoCast,      "auto_cast",           struct { Token token; Ast *expr; }) \
 AST_KIND(_ExprEnd,       "", bool) \