all: implement reference receiver optimization for big structs (#9268)
							parent
							
								
									92e95f127a
								
							
						
					
					
						commit
						945769a4f6
					
				| 
						 | 
					@ -33,6 +33,9 @@ pub fn (node &FnDecl) stringify(t &table.Table, cur_mod string, m2a map[string]s
 | 
				
			||||||
			styp = styp[1..] // remove &
 | 
								styp = styp[1..] // remove &
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		styp = util.no_cur_mod(styp, cur_mod)
 | 
							styp = util.no_cur_mod(styp, cur_mod)
 | 
				
			||||||
 | 
							if node.params[0].is_auto_rec {
 | 
				
			||||||
 | 
								styp = styp.trim('&')
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		receiver = '($m$node.receiver.name $styp) '
 | 
							receiver = '($m$node.receiver.name $styp) '
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		sym := t.get_type_symbol(node.receiver.typ)
 | 
							sym := t.get_type_symbol(node.receiver.typ)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2444,6 +2444,9 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) {
 | 
				
			||||||
			got_typ_sym := c.table.get_type_symbol(got_typ)
 | 
								got_typ_sym := c.table.get_type_symbol(got_typ)
 | 
				
			||||||
			mut exp_typ_sym := c.table.get_type_symbol(exp_type)
 | 
								mut exp_typ_sym := c.table.get_type_symbol(exp_type)
 | 
				
			||||||
			pos := return_stmt.exprs[i].position()
 | 
								pos := return_stmt.exprs[i].position()
 | 
				
			||||||
 | 
								if return_stmt.exprs[i].is_auto_deref_var() {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			if exp_typ_sym.kind == .interface_ {
 | 
								if exp_typ_sym.kind == .interface_ {
 | 
				
			||||||
				c.type_implements(got_typ, exp_type, return_stmt.pos)
 | 
									c.type_implements(got_typ, exp_type, return_stmt.pos)
 | 
				
			||||||
				continue
 | 
									continue
 | 
				
			||||||
| 
						 | 
					@ -2454,12 +2457,18 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) {
 | 
				
			||||||
		if (got_typ.is_ptr() || got_typ.is_pointer())
 | 
							if (got_typ.is_ptr() || got_typ.is_pointer())
 | 
				
			||||||
			&& (!exp_type.is_ptr() && !exp_type.is_pointer()) {
 | 
								&& (!exp_type.is_ptr() && !exp_type.is_pointer()) {
 | 
				
			||||||
			pos := return_stmt.exprs[i].position()
 | 
								pos := return_stmt.exprs[i].position()
 | 
				
			||||||
 | 
								if return_stmt.exprs[i].is_auto_deref_var() {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			c.error('fn `$c.cur_fn.name` expects you to return a non reference type `${c.table.type_to_str(exp_type)}`, but you are returning `${c.table.type_to_str(got_typ)}` instead',
 | 
								c.error('fn `$c.cur_fn.name` expects you to return a non reference type `${c.table.type_to_str(exp_type)}`, but you are returning `${c.table.type_to_str(got_typ)}` instead',
 | 
				
			||||||
				pos)
 | 
									pos)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (exp_type.is_ptr() || exp_type.is_pointer())
 | 
							if (exp_type.is_ptr() || exp_type.is_pointer())
 | 
				
			||||||
			&& (!got_typ.is_ptr() && !got_typ.is_pointer()) && got_typ != table.int_literal_type {
 | 
								&& (!got_typ.is_ptr() && !got_typ.is_pointer()) && got_typ != table.int_literal_type {
 | 
				
			||||||
			pos := return_stmt.exprs[i].position()
 | 
								pos := return_stmt.exprs[i].position()
 | 
				
			||||||
 | 
								if return_stmt.exprs[i].is_auto_deref_var() {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			c.error('fn `$c.cur_fn.name` expects you to return a reference type `${c.table.type_to_str(exp_type)}`, but you are returning `${c.table.type_to_str(got_typ)}` instead',
 | 
								c.error('fn `$c.cur_fn.name` expects you to return a reference type `${c.table.type_to_str(exp_type)}`, but you are returning `${c.table.type_to_str(got_typ)}` instead',
 | 
				
			||||||
				pos)
 | 
									pos)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -4713,7 +4722,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym table.TypeS
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// smartcast takes the expression with the current type which should be smartcasted to the target type in the given scope
 | 
					// smartcast takes the expression with the current type which should be smartcasted to the target type in the given scope
 | 
				
			||||||
fn (c Checker) smartcast_sumtype(expr ast.Expr, cur_type table.Type, to_type table.Type, mut scope ast.Scope) {
 | 
					fn (c &Checker) smartcast_sumtype(expr ast.Expr, cur_type table.Type, to_type table.Type, mut scope ast.Scope) {
 | 
				
			||||||
	match mut expr {
 | 
						match mut expr {
 | 
				
			||||||
		ast.SelectorExpr {
 | 
							ast.SelectorExpr {
 | 
				
			||||||
			mut is_mut := false
 | 
								mut is_mut := false
 | 
				
			||||||
| 
						 | 
					@ -5684,7 +5693,7 @@ pub fn (mut c Checker) error(message string, pos token.Position) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// check `to` has all fields of `from`
 | 
					// check `to` has all fields of `from`
 | 
				
			||||||
fn (c Checker) check_struct_signature(from table.Struct, to table.Struct) bool {
 | 
					fn (c &Checker) check_struct_signature(from table.Struct, to table.Struct) bool {
 | 
				
			||||||
	// Note: `to` can have extra fields
 | 
						// Note: `to` can have extra fields
 | 
				
			||||||
	if from.fields.len == 0 {
 | 
						if from.fields.len == 0 {
 | 
				
			||||||
		return false
 | 
							return false
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4496,7 +4496,18 @@ fn (mut g Gen) return_statement(node ast.Return) {
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			g.write('return ')
 | 
								g.write('return ')
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type)
 | 
							if expr0.is_auto_deref_var() {
 | 
				
			||||||
 | 
								if g.fn_decl.return_type.is_ptr() {
 | 
				
			||||||
 | 
									g.write('&(*')
 | 
				
			||||||
 | 
									g.expr(expr0)
 | 
				
			||||||
 | 
									g.write(')')
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									g.write('*')
 | 
				
			||||||
 | 
									g.expr(expr0)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if free {
 | 
							if free {
 | 
				
			||||||
			expr := node.exprs[0]
 | 
								expr := node.exprs[0]
 | 
				
			||||||
			if expr is ast.Ident {
 | 
								if expr is ast.Ident {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -279,7 +279,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
 | 
				
			||||||
				name: param.name
 | 
									name: param.name
 | 
				
			||||||
				typ: param.typ
 | 
									typ: param.typ
 | 
				
			||||||
				is_mut: param.is_mut
 | 
									is_mut: param.is_mut
 | 
				
			||||||
				is_auto_deref: param.is_mut
 | 
									is_auto_deref: param.is_mut || param.is_auto_rec
 | 
				
			||||||
				pos: param.pos
 | 
									pos: param.pos
 | 
				
			||||||
				is_used: true
 | 
									is_used: true
 | 
				
			||||||
				is_arg: true
 | 
									is_arg: true
 | 
				
			||||||
| 
						 | 
					@ -478,10 +478,22 @@ fn (mut p Parser) fn_receiver(mut params []table.Param, mut rec ReceiverParsingI
 | 
				
			||||||
	if is_atomic {
 | 
						if is_atomic {
 | 
				
			||||||
		rec.typ = rec.typ.set_flag(.atomic_f)
 | 
							rec.typ = rec.typ.set_flag(.atomic_f)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						// optimize method `automatic use fn (a &big_foo) instead of fn (a big_foo)`
 | 
				
			||||||
 | 
						type_sym := p.table.get_type_symbol(rec.typ)
 | 
				
			||||||
 | 
						mut is_auto_rec := false
 | 
				
			||||||
 | 
						if type_sym.kind == .struct_ {
 | 
				
			||||||
 | 
							info := type_sym.info as table.Struct
 | 
				
			||||||
 | 
							if !rec.is_mut && !rec.typ.is_ptr() && info.fields.len > 8 {
 | 
				
			||||||
 | 
								rec.typ = rec.typ.to_ptr()
 | 
				
			||||||
 | 
								is_auto_rec = true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	params << table.Param{
 | 
						params << table.Param{
 | 
				
			||||||
		pos: rec_start_pos
 | 
							pos: rec_start_pos
 | 
				
			||||||
		name: rec.name
 | 
							name: rec.name
 | 
				
			||||||
		is_mut: rec.is_mut
 | 
							is_mut: rec.is_mut
 | 
				
			||||||
 | 
							is_auto_rec: is_auto_rec
 | 
				
			||||||
		typ: rec.typ
 | 
							typ: rec.typ
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	p.check(.rpar)
 | 
						p.check(.rpar)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,12 +57,13 @@ fn (f &Fn) method_equals(o &Fn) bool {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Param {
 | 
					pub struct Param {
 | 
				
			||||||
pub:
 | 
					pub:
 | 
				
			||||||
	pos       token.Position
 | 
						pos         token.Position
 | 
				
			||||||
	name      string
 | 
						name        string
 | 
				
			||||||
	is_mut    bool
 | 
						is_mut      bool
 | 
				
			||||||
	typ       Type
 | 
						is_auto_rec bool
 | 
				
			||||||
	type_pos  token.Position
 | 
						typ         Type
 | 
				
			||||||
	is_hidden bool // interface first arg
 | 
						type_pos    token.Position
 | 
				
			||||||
 | 
						is_hidden   bool // interface first arg
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn (p &Param) equals(o &Param) bool {
 | 
					fn (p &Param) equals(o &Param) bool {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue