Skip to content

Commit c19462b

Browse files
committed
cgen: fix selector smartcasts in generic contexts
1 parent d61fbe8 commit c19462b

2 files changed

Lines changed: 107 additions & 85 deletions

File tree

vlib/v/gen/c/cgen.v

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7200,10 +7200,16 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
72007200
&& exposed_interface_smartcast_type.is_ptr())
72017201
// Interface→interface smartcast: the conversion `I_X_as_I_Y(parent)` returns
72027202
// a struct value, not a pointer, so field access must use `.`, not `->`.
7203+
is_option_unwrapped_interface_ptr := is_interface_smartcast_expr
7204+
&& smartcast_expr_var.orig_type.has_option_or_result()
7205+
&& smartcast_expr_var.orig_type.clear_option_and_result().is_ptr()
72037206
is_interface_to_interface_smartcast := is_interface_smartcast_expr
72047207
&& g.table.final_sym(g.unwrap_generic(smartcast_expr_var.smartcasts.last())).kind == .interface
7208+
&& !is_option_unwrapped_interface_ptr
7209+
unwrapped_autoheap_option_payload_is_ptr := expr_is_unwrapped_autoheap_option
7210+
&& expr_autoheap_option_type.clear_option_and_result().is_ptr()
72057211
left_is_ptr := if expr_is_unwrapped_autoheap_option {
7206-
false
7212+
unwrapped_autoheap_option_payload_is_ptr
72077213
} else if is_interface_to_interface_smartcast {
72087214
false
72097215
} else {

vlib/v/gen/c/utils.v

Lines changed: 100 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -979,15 +979,112 @@ fn (mut g Gen) resolve_selector_smartcast_type(node ast.SelectorExpr) ast.Type {
979979
scope := g.file.scope.innermost(node.pos.pos)
980980
field := scope.find_struct_field(node.expr.str(), node.expr_type, node.field_name)
981981
if field != unsafe { nil } && field.smartcasts.len > 0 {
982+
smartcast_type := field.smartcasts.last()
983+
field_unwrapped_type := field.orig_type.clear_option_and_result()
984+
if field.orig_type.has_option_or_result() && !smartcast_type.has_option_or_result()
985+
&& smartcast_type == field_unwrapped_type {
986+
left_default := if node.expr_type != 0 { node.expr_type } else { field.struct_type }
987+
left_type := g.resolved_expr_type(node.expr, left_default)
988+
resolved_field_type := g.resolved_selector_field_type(node, left_type)
989+
if resolved_field_type != 0 {
990+
return resolved_field_type.clear_option_and_result()
991+
}
992+
}
982993
resolved_sc := g.unwrap_generic(g.recheck_concrete_type(g.exposed_smartcast_type(field.orig_type,
983-
field.smartcasts.last(), field.is_mut)))
994+
smartcast_type, field.is_mut)))
984995
if resolved_sc != 0 {
985996
return resolved_sc
986997
}
987998
}
988999
return 0
9891000
}
9901001

1002+
fn (mut g Gen) resolved_selector_field_type(node ast.SelectorExpr, receiver_type ast.Type) ast.Type {
1003+
if receiver_type == 0 {
1004+
return 0
1005+
}
1006+
sym := g.table.sym(g.unwrap_generic(receiver_type))
1007+
if field := g.table.find_field_with_embeds(sym, node.field_name) {
1008+
mut field_type := field.typ
1009+
match sym.info {
1010+
ast.Struct, ast.Interface, ast.SumType {
1011+
mut generic_names := sym.info.generic_types.map(g.table.sym(it).name)
1012+
mut concrete_types := sym.info.concrete_types.clone()
1013+
if concrete_types.len == 0 && sym.generic_types.len == generic_names.len
1014+
&& sym.generic_types != sym.info.generic_types {
1015+
concrete_types = sym.generic_types.clone()
1016+
}
1017+
mut source_field_type := field.typ
1018+
if sym.info.parent_type.has_flag(.generic) {
1019+
parent_sym := g.table.sym(sym.info.parent_type)
1020+
if parent_field := g.table.find_field_with_embeds(parent_sym, node.field_name) {
1021+
source_field_type = parent_field.typ
1022+
match parent_sym.info {
1023+
ast.Struct, ast.Interface, ast.SumType {
1024+
generic_names =
1025+
parent_sym.info.generic_types.map(g.table.sym(it).name)
1026+
}
1027+
else {}
1028+
}
1029+
}
1030+
}
1031+
if generic_names.len == concrete_types.len && concrete_types.len > 0 {
1032+
mut muttable := unsafe { &ast.Table(g.table) }
1033+
resolved_field_type := muttable.unwrap_generic_type_ex(source_field_type,
1034+
generic_names, concrete_types, true)
1035+
if resolved_field_type != source_field_type {
1036+
field_type = resolved_field_type
1037+
} else {
1038+
if converted_field_type := muttable.convert_generic_type(source_field_type,
1039+
generic_names, concrete_types)
1040+
{
1041+
field_type = converted_field_type
1042+
}
1043+
}
1044+
}
1045+
}
1046+
ast.GenericInst {
1047+
parent_sym := g.table.sym(ast.new_type(sym.info.parent_idx))
1048+
mut source_field_type := field.typ
1049+
if parent_field := g.table.find_field_with_embeds(parent_sym, node.field_name) {
1050+
source_field_type = parent_field.typ
1051+
}
1052+
match parent_sym.info {
1053+
ast.Struct, ast.Interface, ast.SumType {
1054+
generic_names := parent_sym.info.generic_types.map(g.table.sym(it).name)
1055+
if generic_names.len == sym.info.concrete_types.len
1056+
&& sym.info.concrete_types.len > 0 {
1057+
mut muttable := unsafe { &ast.Table(g.table) }
1058+
resolved_field_type := muttable.unwrap_generic_type_ex(source_field_type,
1059+
generic_names, sym.info.concrete_types, true)
1060+
if resolved_field_type != source_field_type {
1061+
field_type = resolved_field_type
1062+
} else {
1063+
if converted_field_type := muttable.convert_generic_type(source_field_type,
1064+
generic_names, sym.info.concrete_types)
1065+
{
1066+
field_type = converted_field_type
1067+
}
1068+
}
1069+
}
1070+
}
1071+
else {}
1072+
}
1073+
}
1074+
else {}
1075+
}
1076+
1077+
$if trace_ci_fixes ? {
1078+
if g.file.path.contains('binary_search_tree.v') && node.expr is ast.Ident
1079+
&& node.expr.name == 'tree' {
1080+
eprintln('resolved selector ${node.expr.name}.${node.field_name} left=${g.table.type_to_str(receiver_type)} field=${g.table.type_to_str(field.typ)} final=${g.table.type_to_str(field_type)} expr_typ=${g.table.type_to_str(node.typ)}')
1081+
}
1082+
}
1083+
return g.unwrap_generic(g.recheck_concrete_type(field_type))
1084+
}
1085+
return 0
1086+
}
1087+
9911088
fn (mut g Gen) resolved_expr_type(expr ast.Expr, default_typ ast.Type) ast.Type {
9921089
match expr {
9931090
ast.ParExpr {
@@ -1179,89 +1276,8 @@ fn (mut g Gen) resolved_expr_type(expr ast.Expr, default_typ ast.Type) ast.Type
11791276
left_default := if expr.expr_type != 0 { expr.expr_type } else { default_typ }
11801277
left_type := g.recheck_concrete_type(g.resolved_expr_type(expr.expr, left_default))
11811278
if left_type != 0 {
1182-
sym := g.table.sym(g.unwrap_generic(left_type))
1183-
if field := g.table.find_field_with_embeds(sym, expr.field_name) {
1184-
mut field_type := field.typ
1185-
match sym.info {
1186-
ast.Struct, ast.Interface, ast.SumType {
1187-
mut generic_names := sym.info.generic_types.map(g.table.sym(it).name)
1188-
mut concrete_types := sym.info.concrete_types.clone()
1189-
if concrete_types.len == 0 && sym.generic_types.len == generic_names.len
1190-
&& sym.generic_types != sym.info.generic_types {
1191-
concrete_types = sym.generic_types.clone()
1192-
}
1193-
mut source_field_type := field.typ
1194-
if sym.info.parent_type.has_flag(.generic) {
1195-
parent_sym := g.table.sym(sym.info.parent_type)
1196-
if parent_field := g.table.find_field_with_embeds(parent_sym,
1197-
expr.field_name)
1198-
{
1199-
source_field_type = parent_field.typ
1200-
match parent_sym.info {
1201-
ast.Struct, ast.Interface, ast.SumType {
1202-
generic_names =
1203-
parent_sym.info.generic_types.map(g.table.sym(it).name)
1204-
}
1205-
else {}
1206-
}
1207-
}
1208-
}
1209-
if generic_names.len == concrete_types.len && concrete_types.len > 0 {
1210-
mut muttable := unsafe { &ast.Table(g.table) }
1211-
resolved_field_type := muttable.unwrap_generic_type_ex(source_field_type,
1212-
generic_names, concrete_types, true)
1213-
if resolved_field_type != source_field_type {
1214-
field_type = resolved_field_type
1215-
} else {
1216-
if converted_field_type := muttable.convert_generic_type(source_field_type,
1217-
generic_names, concrete_types)
1218-
{
1219-
field_type = converted_field_type
1220-
}
1221-
}
1222-
}
1223-
}
1224-
ast.GenericInst {
1225-
parent_sym := g.table.sym(ast.new_type(sym.info.parent_idx))
1226-
mut source_field_type := field.typ
1227-
if parent_field := g.table.find_field_with_embeds(parent_sym,
1228-
expr.field_name)
1229-
{
1230-
source_field_type = parent_field.typ
1231-
}
1232-
match parent_sym.info {
1233-
ast.Struct, ast.Interface, ast.SumType {
1234-
generic_names :=
1235-
parent_sym.info.generic_types.map(g.table.sym(it).name)
1236-
if generic_names.len == sym.info.concrete_types.len
1237-
&& sym.info.concrete_types.len > 0 {
1238-
mut muttable := unsafe { &ast.Table(g.table) }
1239-
resolved_field_type := muttable.unwrap_generic_type_ex(source_field_type,
1240-
generic_names, sym.info.concrete_types, true)
1241-
if resolved_field_type != source_field_type {
1242-
field_type = resolved_field_type
1243-
} else {
1244-
if converted_field_type := muttable.convert_generic_type(source_field_type,
1245-
generic_names, sym.info.concrete_types)
1246-
{
1247-
field_type = converted_field_type
1248-
}
1249-
}
1250-
}
1251-
}
1252-
else {}
1253-
}
1254-
}
1255-
else {}
1256-
}
1257-
1258-
$if trace_ci_fixes ? {
1259-
if g.file.path.contains('binary_search_tree.v') && expr.expr is ast.Ident
1260-
&& expr.expr.name == 'tree' {
1261-
eprintln('resolved selector ${expr.expr.name}.${expr.field_name} left=${g.table.type_to_str(left_type)} field=${g.table.type_to_str(field.typ)} final=${g.table.type_to_str(field_type)} expr_typ=${g.table.type_to_str(expr.typ)}')
1262-
}
1263-
}
1264-
mut resolved_type := g.unwrap_generic(g.recheck_concrete_type(field_type))
1279+
mut resolved_type := g.resolved_selector_field_type(expr, left_type)
1280+
if resolved_type != 0 {
12651281
if expr.or_block.kind != .absent {
12661282
resolved_type = resolved_type.clear_option_and_result()
12671283
}

0 commit comments

Comments
 (0)