Fix some panics related to nil values
This commit is contained in:
		
							
								
								
									
										25
									
								
								salix.go
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								salix.go
									
									
									
									
									
								
							@@ -404,7 +404,14 @@ func (t *Template) getIndex(i ast.Index, local map[string]any) (any, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	var out reflect.Value
 | 
						var out reflect.Value
 | 
				
			||||||
	rval := reflect.ValueOf(val)
 | 
						rval := reflect.ValueOf(val)
 | 
				
			||||||
 | 
						if !rval.IsValid() {
 | 
				
			||||||
 | 
							return nil, ast.PosError(i, "%s: cannot get index of nil value", valueToString(i))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	rindex := reflect.ValueOf(index)
 | 
						rindex := reflect.ValueOf(index)
 | 
				
			||||||
 | 
						if !rval.IsValid() {
 | 
				
			||||||
 | 
							return nil, ast.PosError(i, "%s: cannot use nil value as an index", valueToString(i))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch rval.Kind() {
 | 
						switch rval.Kind() {
 | 
				
			||||||
	case reflect.Slice, reflect.Array, reflect.String:
 | 
						case reflect.Slice, reflect.Array, reflect.String:
 | 
				
			||||||
		intType := reflect.TypeOf(0)
 | 
							intType := reflect.TypeOf(0)
 | 
				
			||||||
@@ -448,9 +455,15 @@ func (t *Template) getField(fa ast.FieldAccess, local map[string]any) (any, erro
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	rval := reflect.ValueOf(val)
 | 
						rval := reflect.ValueOf(val)
 | 
				
			||||||
 | 
						if !rval.IsValid() {
 | 
				
			||||||
 | 
							return nil, ast.PosError(fa, "%s: cannot get field of nil value", valueToString(fa))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	for rval.Kind() == reflect.Pointer {
 | 
						for rval.Kind() == reflect.Pointer {
 | 
				
			||||||
		rval = rval.Elem()
 | 
							rval = rval.Elem()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if rval.Kind() != reflect.Struct || rval.NumField() == 0 {
 | 
				
			||||||
 | 
							return nil, ast.PosError(fa, "%s: value has no fields", valueToString(fa))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	field := rval.FieldByName(fa.Name.Value)
 | 
						field := rval.FieldByName(fa.Name.Value)
 | 
				
			||||||
	if !field.IsValid() {
 | 
						if !field.IsValid() {
 | 
				
			||||||
		return nil, ast.PosError(fa, "%s: no such field: %s", valueToString(fa), fa.Name.Value)
 | 
							return nil, ast.PosError(fa, "%s: no such field: %s", valueToString(fa), fa.Name.Value)
 | 
				
			||||||
@@ -468,6 +481,9 @@ func (t *Template) execMethodCall(mc ast.MethodCall, local map[string]any) (any,
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	rval := reflect.ValueOf(val)
 | 
						rval := reflect.ValueOf(val)
 | 
				
			||||||
 | 
						if !rval.IsValid() {
 | 
				
			||||||
 | 
							return nil, ast.PosError(mc, "%s: cannot call method on nil value", valueToString(mc))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	for rval.Kind() == reflect.Pointer {
 | 
						for rval.Kind() == reflect.Pointer {
 | 
				
			||||||
		rval = rval.Elem()
 | 
							rval = rval.Elem()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -487,6 +503,10 @@ func (t *Template) execMethodCall(mc ast.MethodCall, local map[string]any) (any,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// execFunc executes a function call
 | 
					// execFunc executes a function call
 | 
				
			||||||
func (t *Template) execFunc(fn reflect.Value, node ast.Node, args []ast.Node, local map[string]any) (any, error) {
 | 
					func (t *Template) execFunc(fn reflect.Value, node ast.Node, args []ast.Node, local map[string]any) (any, error) {
 | 
				
			||||||
 | 
						if !fn.IsValid() {
 | 
				
			||||||
 | 
							return nil, ast.PosError(node, "%s: cannot call nil function", valueToString(node))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fnType := fn.Type()
 | 
						fnType := fn.Type()
 | 
				
			||||||
	lastIndex := fnType.NumIn() - 1
 | 
						lastIndex := fnType.NumIn() - 1
 | 
				
			||||||
	isVariadic := fnType.IsVariadic()
 | 
						isVariadic := fnType.IsVariadic()
 | 
				
			||||||
@@ -525,12 +545,15 @@ func (t *Template) execFunc(fn reflect.Value, node ast.Node, args []ast.Node, lo
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret := fn.Call(params)
 | 
						ret := fn.Call(params)
 | 
				
			||||||
 | 
						for ret[0].Kind() == reflect.Pointer {
 | 
				
			||||||
 | 
							ret[0] = ret[0].Elem()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if len(ret) == 1 {
 | 
						if len(ret) == 1 {
 | 
				
			||||||
		retv := ret[0].Interface()
 | 
							retv := ret[0].Interface()
 | 
				
			||||||
		if err, ok := retv.(error); ok {
 | 
							if err, ok := retv.(error); ok {
 | 
				
			||||||
			return nil, ast.PosError(node, "%s: %w", valueToString(node), err)
 | 
								return nil, ast.PosError(node, "%s: %w", valueToString(node), err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return ret[0].Interface(), nil
 | 
							return retv, nil
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if ret[1].IsNil() {
 | 
							if ret[1].IsNil() {
 | 
				
			||||||
			return ret[0].Interface(), nil
 | 
								return ret[0].Interface(), nil
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user