Browse Source

Improve union variant assignment determination

gingerBill 3 years ago
parent
commit
a4308e7246
1 changed files with 36 additions and 0 deletions
  1. 36 0
      src/check_expr.cpp

+ 36 - 0
src/check_expr.cpp

@@ -673,6 +673,42 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type
 				return 1;
 				return 1;
 			}
 			}
 		}
 		}
+
+		// TODO(bill): Determine which rule is a better on in practice
+		#if 1
+			if (dst->Union.variants.count == 1) {
+				Type *vt = dst->Union.variants[0];
+				i64 score = check_distance_between_types(c, operand, vt);
+				if (score >= 0) {
+					return score+2;
+				}
+			}
+		#else
+			// NOTE(bill): check to see you can assign to it with one of the variants?
+			i64 prev_lowest_score = -1;
+			i64 lowest_score = -1;
+			for_array(i, dst->Union.variants) {
+				Type *vt = dst->Union.variants[i];
+				i64 score = check_distance_between_types(c, operand, vt);
+				if (score >= 0) {
+					if (lowest_score < 0) {
+						lowest_score = score;
+					} else {
+						if (prev_lowest_score < 0) {
+							prev_lowest_score = lowest_score;
+						} else {
+							prev_lowest_score = gb_min(prev_lowest_score, lowest_score);
+						}
+						lowest_score = gb_min(lowest_score, score);
+					}
+				}
+			}
+			if (lowest_score >= 0) {
+				if (prev_lowest_score != lowest_score) { // remove possible ambiguities
+					return lowest_score+2;
+				}
+			}
+		#endif
 	}
 	}
 
 
 	if (is_type_relative_pointer(dst)) {
 	if (is_type_relative_pointer(dst)) {