From b15ae734633722b23c20d7ba58d0b3cb83e1559a Mon Sep 17 00:00:00 2001 From: visualfc Date: Thu, 16 Nov 2023 22:01:56 +0800 Subject: [PATCH 01/16] record.UpdateType --- ast.go | 19 ++++++++++++++++++- codebuild.go | 18 ++++++++++++++++++ package.go | 1 + template.go | 8 +++++++- type_var_and_const.go | 3 +++ 5 files changed, 47 insertions(+), 2 deletions(-) diff --git a/ast.go b/ast.go index 084cc36d..00f2da23 100644 --- a/ast.go +++ b/ast.go @@ -175,6 +175,13 @@ func toBasicType(pkg *Package, t *types.Basic) ast.Expr { return &ast.Ident{Name: t.Name()} } +func isBasicUntyped(typ types.Type) bool { + if t, ok := typ.(*types.Basic); ok { + return (t.Info() & types.IsUntyped) != 0 + } + return false +} + func isUntyped(pkg *Package, typ types.Type) bool { switch t := typ.(type) { case *types.Basic: @@ -734,6 +741,9 @@ func matchTypeCast(pkg *Package, typ types.Type, fn *internal.Elem, args []*inte fnVal = &ast.ParenExpr{X: fnVal} } if len(args) == 1 && ConvertibleTo(pkg, args[0].Type, typ) { + if pkg.cb.rec != nil && isBasicUntyped(args[0].Type) { + pkg.cb.rec.UpdateType(args[0], typ) + } if args[0].CVal != nil { if t, ok := typ.(*types.Named); ok { o := t.Obj() @@ -1179,7 +1189,14 @@ func (p *MatchError) Error() string { } // TODO: use matchType to all assignable check -func matchType(pkg *Package, arg *internal.Elem, param types.Type, at interface{}) error { +func matchType(pkg *Package, arg *internal.Elem, param types.Type, at interface{}) (r error) { + if pkg.cb.rec != nil && isBasicUntyped(arg.Type) { + defer func() { + if r == nil { + pkg.cb.rec.UpdateType(arg, param) + } + }() + } if debugMatch { cval := "" if arg.CVal != nil { diff --git a/codebuild.go b/codebuild.go index ece39978..2af7fe65 100644 --- a/codebuild.go +++ b/codebuild.go @@ -1075,6 +1075,9 @@ func (p *CodeBuilder) StructLit(typ types.Type, arity int, keyVal bool, src ...a pos, "cannot use %s (type %v) as type %v in value of field %s", src, args[i+1].Type, eltTy, eltName) } + if pkg.cb.rec != nil && isBasicUntyped(args[i+1].Type) { + pkg.cb.rec.UpdateType(args[i+1], eltTy) + } elts[i>>1] = &ast.KeyValueExpr{Key: ident(eltName), Value: args[i+1].Val} } } else if arity != n { @@ -1097,6 +1100,9 @@ func (p *CodeBuilder) StructLit(typ types.Type, arity int, keyVal bool, src ...a pos, "cannot use %s (type %v) as type %v in value of field %s", src, arg.Type, eltTy, t.Field(i).Name()) } + if pkg.cb.rec != nil && isBasicUntyped(arg.Type) { + pkg.cb.rec.UpdateType(arg, eltTy) + } } } p.stk.Ret(arity, &internal.Elem{ @@ -1145,6 +1151,18 @@ func (p *CodeBuilder) Slice(slice3 bool, src ...ast.Node) *CodeBuilder { // a[i: if slice3 { exprMax = args[3].Val } + if p.rec != nil { + if isBasicUntyped(args[1].Type) { + p.rec.UpdateType(args[1], types.Default(args[1].Type)) + } + if isBasicUntyped(args[2].Type) { + p.rec.UpdateType(args[2], types.Default(args[2].Type)) + } + if slice3 && isBasicUntyped(args[3].Type) { + p.rec.UpdateType(args[3], types.Default(args[3].Type)) + } + } + // TODO: check type elem := &internal.Elem{ Val: &ast.SliceExpr{ diff --git a/package.go b/package.go index 861e05b4..ef3aab41 100644 --- a/package.go +++ b/package.go @@ -73,6 +73,7 @@ func fatal(msg string) { type Recorder interface { // Member maps identifiers to the objects they denote. Member(id ast.Node, obj types.Object) + UpdateType(e *Element, typ types.Type) } // ---------------------------------------------------------------------------- diff --git a/template.go b/template.go index 621f2327..cd0294e4 100644 --- a/template.go +++ b/template.go @@ -225,7 +225,13 @@ func DefaultConv(pkg *Package, t types.Type, pv *Element) types.Type { log.Panicln("==> DefaultConv failed: overload functions have no default type") } default: - return types.Default(t) + if isBasicUntyped(typ) { + typ := types.Default(t) + // if pkg.cb.rec != nil && pv != nil { + // pkg.cb.rec.UpdateType(pv, typ) + // } + return typ + } } return t } diff --git a/type_var_and_const.go b/type_var_and_const.go index 86c01bae..9dffa66a 100644 --- a/type_var_and_const.go +++ b/type_var_and_const.go @@ -363,6 +363,9 @@ func (p *ValueDecl) endInit(cb *CodeBuilder, arity int) *ValueDecl { if values != nil { values[i] = parg.Val } + if pkg.cb.rec != nil && isBasicUntyped(rets[i].Type) { + pkg.cb.rec.UpdateType(rets[i], retType) + } if old := p.scope.Insert(types.NewVar(p.pos, pkg.Types, name, retType)); old != nil { if p.tok != token.DEFINE { oldpos := cb.fset.Position(old.Pos()) From 977c2dec83498fe3025465a512f911e8c5b5730d Mon Sep 17 00:00:00 2001 From: visualfc Date: Tue, 21 Nov 2023 08:25:26 +0800 Subject: [PATCH 02/16] x --- ast.go | 10 +++++++++- template.go | 6 +++--- type_var_and_const.go | 3 +++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/ast.go b/ast.go index 00f2da23..71079ea9 100644 --- a/ast.go +++ b/ast.go @@ -1193,7 +1193,15 @@ func matchType(pkg *Package, arg *internal.Elem, param types.Type, at interface{ if pkg.cb.rec != nil && isBasicUntyped(arg.Type) { defer func() { if r == nil { - pkg.cb.rec.UpdateType(arg, param) + typ := param + retry: + switch t := typ.(type) { + case *unboundFuncParam: + typ = t.tBound + goto retry + case *types.Basic: + pkg.cb.rec.UpdateType(arg, t) + } } }() } diff --git a/template.go b/template.go index cd0294e4..284b8cbe 100644 --- a/template.go +++ b/template.go @@ -227,9 +227,9 @@ func DefaultConv(pkg *Package, t types.Type, pv *Element) types.Type { default: if isBasicUntyped(typ) { typ := types.Default(t) - // if pkg.cb.rec != nil && pv != nil { - // pkg.cb.rec.UpdateType(pv, typ) - // } + if pkg.cb.rec != nil && pv != nil { + pkg.cb.rec.UpdateType(pv, typ) + } return typ } } diff --git a/type_var_and_const.go b/type_var_and_const.go index 9dffa66a..5ddf6538 100644 --- a/type_var_and_const.go +++ b/type_var_and_const.go @@ -328,6 +328,9 @@ func (p *ValueDecl) endInit(cb *CodeBuilder, arity int) *ValueDecl { if err := matchType(pkg, ret, typ, "assignment"); err != nil { panic(err) } + if cb.rec != nil && isBasicUntyped(ret.Type) { + cb.rec.UpdateType(ret, typ) + } if values != nil { // ret.Val may be changed values[i] = ret.Val } From 3b1d6341317298dae5dedab5ea0e3fa14bc40f54 Mon Sep 17 00:00:00 2001 From: visualfc Date: Wed, 22 Nov 2023 21:48:37 +0800 Subject: [PATCH 03/16] rec.UpdateUntyped binary/unary --- ast.go | 15 +++++++++++++-- codebuild.go | 23 ++++++++++++++++++----- package.go | 2 +- package_test.go | 2 ++ template.go | 8 +------- type_var_and_const.go | 6 ++++-- 6 files changed, 39 insertions(+), 17 deletions(-) diff --git a/ast.go b/ast.go index 71079ea9..9748b965 100644 --- a/ast.go +++ b/ast.go @@ -714,6 +714,15 @@ retry: switch t := fn.Val.(type) { case *ast.BinaryExpr: t.X, t.Y = checkParenExpr(args[0].Val), checkParenExpr(args[1].Val) + // update untyped + if pkg.cb.rec != nil { + if isBasicUntyped(args[0].Type) { + pkg.cb.rec.UpdateUntyped(args[0], tyRet) + } + if (t.Op != token.SHL && t.Op != token.SHR) && isBasicUntyped(args[1].Type) { + pkg.cb.rec.UpdateUntyped(args[1], tyRet) + } + } return &internal.Elem{Val: t, Type: tyRet, CVal: cval}, nil case *ast.UnaryExpr: t.X = args[0].Val @@ -741,8 +750,9 @@ func matchTypeCast(pkg *Package, typ types.Type, fn *internal.Elem, args []*inte fnVal = &ast.ParenExpr{X: fnVal} } if len(args) == 1 && ConvertibleTo(pkg, args[0].Type, typ) { + // update untyped if pkg.cb.rec != nil && isBasicUntyped(args[0].Type) { - pkg.cb.rec.UpdateType(args[0], typ) + pkg.cb.rec.UpdateUntyped(args[0], typ) } if args[0].CVal != nil { if t, ok := typ.(*types.Named); ok { @@ -1190,6 +1200,7 @@ func (p *MatchError) Error() string { // TODO: use matchType to all assignable check func matchType(pkg *Package, arg *internal.Elem, param types.Type, at interface{}) (r error) { + // update untyped if pkg.cb.rec != nil && isBasicUntyped(arg.Type) { defer func() { if r == nil { @@ -1200,7 +1211,7 @@ func matchType(pkg *Package, arg *internal.Elem, param types.Type, at interface{ typ = t.tBound goto retry case *types.Basic: - pkg.cb.rec.UpdateType(arg, t) + pkg.cb.rec.UpdateUntyped(arg, t) } } }() diff --git a/codebuild.go b/codebuild.go index 2af7fe65..3a58b4ae 100644 --- a/codebuild.go +++ b/codebuild.go @@ -1075,8 +1075,9 @@ func (p *CodeBuilder) StructLit(typ types.Type, arity int, keyVal bool, src ...a pos, "cannot use %s (type %v) as type %v in value of field %s", src, args[i+1].Type, eltTy, eltName) } + // update untyped if pkg.cb.rec != nil && isBasicUntyped(args[i+1].Type) { - pkg.cb.rec.UpdateType(args[i+1], eltTy) + pkg.cb.rec.UpdateUntyped(args[i+1], eltTy) } elts[i>>1] = &ast.KeyValueExpr{Key: ident(eltName), Value: args[i+1].Val} } @@ -1100,8 +1101,9 @@ func (p *CodeBuilder) StructLit(typ types.Type, arity int, keyVal bool, src ...a pos, "cannot use %s (type %v) as type %v in value of field %s", src, arg.Type, eltTy, t.Field(i).Name()) } + // update untyped if pkg.cb.rec != nil && isBasicUntyped(arg.Type) { - pkg.cb.rec.UpdateType(arg, eltTy) + pkg.cb.rec.UpdateUntyped(arg, eltTy) } } } @@ -1151,15 +1153,16 @@ func (p *CodeBuilder) Slice(slice3 bool, src ...ast.Node) *CodeBuilder { // a[i: if slice3 { exprMax = args[3].Val } + // update untyped if p.rec != nil { if isBasicUntyped(args[1].Type) { - p.rec.UpdateType(args[1], types.Default(args[1].Type)) + p.rec.UpdateUntyped(args[1], types.Default(args[1].Type)) } if isBasicUntyped(args[2].Type) { - p.rec.UpdateType(args[2], types.Default(args[2].Type)) + p.rec.UpdateUntyped(args[2], types.Default(args[2].Type)) } if slice3 && isBasicUntyped(args[3].Type) { - p.rec.UpdateType(args[3], types.Default(args[3].Type)) + p.rec.UpdateUntyped(args[3], types.Default(args[3].Type)) } } @@ -2072,6 +2075,16 @@ retry: if !ComparableTo(pkg, args[0], args[1]) { return nil, errors.New("mismatched types") } + // update untyped + if pkg.cb.rec != nil { + b0 := isBasicUntyped(args[0].Type) + b1 := isBasicUntyped(args[1].Type) + if b0 && !b1 { + pkg.cb.rec.UpdateUntyped(args[0], args[1].Type) + } else if b1 && !b0 { + pkg.cb.rec.UpdateUntyped(args[1], args[0].Type) + } + } ret = &internal.Elem{ Val: &ast.BinaryExpr{ X: checkParenExpr(args[0].Val), Op: op, diff --git a/package.go b/package.go index ef3aab41..b88aba01 100644 --- a/package.go +++ b/package.go @@ -73,7 +73,7 @@ func fatal(msg string) { type Recorder interface { // Member maps identifiers to the objects they denote. Member(id ast.Node, obj types.Object) - UpdateType(e *Element, typ types.Type) + UpdateUntyped(e *Element, typ types.Type) } // ---------------------------------------------------------------------------- diff --git a/package_test.go b/package_test.go index b10031d4..e24db31c 100644 --- a/package_test.go +++ b/package_test.go @@ -52,6 +52,8 @@ type eventRecorder struct{} func (p eventRecorder) Member(id ast.Node, obj types.Object) { } +func (p eventRecorder) UpdateUntyped(e *gox.Element, typ types.Type) { +} func newMainPackage( implicitCast ...func(pkg *gox.Package, V, T types.Type, pv *gox.Element) bool) *gox.Package { diff --git a/template.go b/template.go index 284b8cbe..621f2327 100644 --- a/template.go +++ b/template.go @@ -225,13 +225,7 @@ func DefaultConv(pkg *Package, t types.Type, pv *Element) types.Type { log.Panicln("==> DefaultConv failed: overload functions have no default type") } default: - if isBasicUntyped(typ) { - typ := types.Default(t) - if pkg.cb.rec != nil && pv != nil { - pkg.cb.rec.UpdateType(pv, typ) - } - return typ - } + return types.Default(t) } return t } diff --git a/type_var_and_const.go b/type_var_and_const.go index 5ddf6538..91322176 100644 --- a/type_var_and_const.go +++ b/type_var_and_const.go @@ -328,8 +328,9 @@ func (p *ValueDecl) endInit(cb *CodeBuilder, arity int) *ValueDecl { if err := matchType(pkg, ret, typ, "assignment"); err != nil { panic(err) } + // update untyped if cb.rec != nil && isBasicUntyped(ret.Type) { - cb.rec.UpdateType(ret, typ) + cb.rec.UpdateUntyped(ret, typ) } if values != nil { // ret.Val may be changed values[i] = ret.Val @@ -366,8 +367,9 @@ func (p *ValueDecl) endInit(cb *CodeBuilder, arity int) *ValueDecl { if values != nil { values[i] = parg.Val } + // update untyped if pkg.cb.rec != nil && isBasicUntyped(rets[i].Type) { - pkg.cb.rec.UpdateType(rets[i], retType) + pkg.cb.rec.UpdateUntyped(rets[i], retType) } if old := p.scope.Insert(types.NewVar(p.pos, pkg.Types, name, retType)); old != nil { if p.tok != token.DEFINE { From 97390fa05fe318c76738a811e452e7826d3ee945 Mon Sep 17 00:00:00 2001 From: visualfc Date: Thu, 23 Nov 2023 09:22:26 +0800 Subject: [PATCH 04/16] binaryOp check kind --- ast.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ast.go b/ast.go index 9748b965..218d5bc7 100644 --- a/ast.go +++ b/ast.go @@ -715,11 +715,12 @@ retry: case *ast.BinaryExpr: t.X, t.Y = checkParenExpr(args[0].Val), checkParenExpr(args[1].Val) // update untyped - if pkg.cb.rec != nil { + kind := binaryOpKinds[t.Op] + if kind != binaryOpCompare && pkg.cb.rec != nil { if isBasicUntyped(args[0].Type) { pkg.cb.rec.UpdateUntyped(args[0], tyRet) } - if (t.Op != token.SHL && t.Op != token.SHR) && isBasicUntyped(args[1].Type) { + if kind != binaryOpShift && isBasicUntyped(args[1].Type) { pkg.cb.rec.UpdateUntyped(args[1], tyRet) } } From 2af3a3bff245af672d01f5d7d13126293e4d7843 Mon Sep 17 00:00:00 2001 From: visualfc Date: Thu, 23 Nov 2023 10:50:43 +0800 Subject: [PATCH 05/16] CodeBuilder: recordUpdateUntyped --- ast.go | 37 +++-------------- codebuild.go | 97 ++++++++++++++++++++++++++++++------------- type_var_and_const.go | 10 +---- 3 files changed, 76 insertions(+), 68 deletions(-) diff --git a/ast.go b/ast.go index 218d5bc7..5dc5d32d 100644 --- a/ast.go +++ b/ast.go @@ -481,6 +481,7 @@ func binaryOp(cb *CodeBuilder, tok token.Token, args []*internal.Elem) constant. if tok == token.QUO && isNormalInt(cb, args[0]) && isNormalInt(cb, args[1]) { tok = token.QUO_ASSIGN // issue #805 } + cb.recordUpdateUntypedBinaryOp(tok, args, nil) return doBinaryOp(a, tok, b) } } @@ -714,16 +715,7 @@ retry: switch t := fn.Val.(type) { case *ast.BinaryExpr: t.X, t.Y = checkParenExpr(args[0].Val), checkParenExpr(args[1].Val) - // update untyped - kind := binaryOpKinds[t.Op] - if kind != binaryOpCompare && pkg.cb.rec != nil { - if isBasicUntyped(args[0].Type) { - pkg.cb.rec.UpdateUntyped(args[0], tyRet) - } - if kind != binaryOpShift && isBasicUntyped(args[1].Type) { - pkg.cb.rec.UpdateUntyped(args[1], tyRet) - } - } + pkg.cb.recordUpdateUntypedBinaryOp(t.Op, args, tyRet) return &internal.Elem{Val: t, Type: tyRet, CVal: cval}, nil case *ast.UnaryExpr: t.X = args[0].Val @@ -751,10 +743,7 @@ func matchTypeCast(pkg *Package, typ types.Type, fn *internal.Elem, args []*inte fnVal = &ast.ParenExpr{X: fnVal} } if len(args) == 1 && ConvertibleTo(pkg, args[0].Type, typ) { - // update untyped - if pkg.cb.rec != nil && isBasicUntyped(args[0].Type) { - pkg.cb.rec.UpdateUntyped(args[0], typ) - } + pkg.cb.recordUpdateUntyped(args[0], typ) if args[0].CVal != nil { if t, ok := typ.(*types.Named); ok { o := t.Obj() @@ -1041,9 +1030,11 @@ func matchFuncType( func matchFuncArgs( pkg *Package, args []*internal.Elem, sig *types.Signature, at interface{}) error { for i, arg := range args { - if err := matchType(pkg, arg, getParam(sig, i).Type(), at); err != nil { + typ := getParam(sig, i).Type() + if err := matchType(pkg, arg, typ, at); err != nil { return err } + pkg.cb.recordUpdateUntypedParam(arg, typ) } return nil } @@ -1201,22 +1192,6 @@ func (p *MatchError) Error() string { // TODO: use matchType to all assignable check func matchType(pkg *Package, arg *internal.Elem, param types.Type, at interface{}) (r error) { - // update untyped - if pkg.cb.rec != nil && isBasicUntyped(arg.Type) { - defer func() { - if r == nil { - typ := param - retry: - switch t := typ.(type) { - case *unboundFuncParam: - typ = t.tBound - goto retry - case *types.Basic: - pkg.cb.rec.UpdateUntyped(arg, t) - } - } - }() - } if debugMatch { cval := "" if arg.CVal != nil { diff --git a/codebuild.go b/codebuild.go index 3a58b4ae..87a7b26c 100644 --- a/codebuild.go +++ b/codebuild.go @@ -1075,10 +1075,7 @@ func (p *CodeBuilder) StructLit(typ types.Type, arity int, keyVal bool, src ...a pos, "cannot use %s (type %v) as type %v in value of field %s", src, args[i+1].Type, eltTy, eltName) } - // update untyped - if pkg.cb.rec != nil && isBasicUntyped(args[i+1].Type) { - pkg.cb.rec.UpdateUntyped(args[i+1], eltTy) - } + pkg.cb.recordUpdateUntyped(args[i+1], eltTy) elts[i>>1] = &ast.KeyValueExpr{Key: ident(eltName), Value: args[i+1].Val} } } else if arity != n { @@ -1101,10 +1098,7 @@ func (p *CodeBuilder) StructLit(typ types.Type, arity int, keyVal bool, src ...a pos, "cannot use %s (type %v) as type %v in value of field %s", src, arg.Type, eltTy, t.Field(i).Name()) } - // update untyped - if pkg.cb.rec != nil && isBasicUntyped(arg.Type) { - pkg.cb.rec.UpdateUntyped(arg, eltTy) - } + pkg.cb.recordUpdateUntyped(arg, eltTy) } } p.stk.Ret(arity, &internal.Elem{ @@ -1153,17 +1147,11 @@ func (p *CodeBuilder) Slice(slice3 bool, src ...ast.Node) *CodeBuilder { // a[i: if slice3 { exprMax = args[3].Val } - // update untyped - if p.rec != nil { - if isBasicUntyped(args[1].Type) { - p.rec.UpdateUntyped(args[1], types.Default(args[1].Type)) - } - if isBasicUntyped(args[2].Type) { - p.rec.UpdateUntyped(args[2], types.Default(args[2].Type)) - } - if slice3 && isBasicUntyped(args[3].Type) { - p.rec.UpdateUntyped(args[3], types.Default(args[3].Type)) - } + + p.recordUpdateUntypedDefault(args[1]) + p.recordUpdateUntypedDefault(args[2]) + if slice3 { + p.recordUpdateUntypedDefault(args[3]) } // TODO: check type @@ -2075,16 +2063,9 @@ retry: if !ComparableTo(pkg, args[0], args[1]) { return nil, errors.New("mismatched types") } - // update untyped - if pkg.cb.rec != nil { - b0 := isBasicUntyped(args[0].Type) - b1 := isBasicUntyped(args[1].Type) - if b0 && !b1 { - pkg.cb.rec.UpdateUntyped(args[0], args[1].Type) - } else if b1 && !b0 { - pkg.cb.rec.UpdateUntyped(args[1], args[0].Type) - } - } + + pkg.cb.recordUpdateUntypedBinaryOp(op, args, nil) + ret = &internal.Elem{ Val: &ast.BinaryExpr{ X: checkParenExpr(args[0].Val), Op: op, @@ -2668,3 +2649,61 @@ func (p *CodeBuilder) InternalStack() *InternalStack { } // ---------------------------------------------------------------------------- + +func (p *CodeBuilder) recordUpdateUntypedDefault(e *internal.Elem) { + if p.rec == nil { + return + } + if isBasicUntyped(e.Type) { + p.rec.UpdateUntyped(e, types.Default(e.Type)) + } +} + +func (p *CodeBuilder) recordUpdateUntyped(e *internal.Elem, typ types.Type) { + if p.rec == nil { + return + } + if isBasicUntyped(e.Type) && !isBasicUntyped(typ) { + p.rec.UpdateUntyped(e, typ) + } +} + +func (p *CodeBuilder) recordUpdateUntypedParam(e *internal.Elem, param types.Type) { + if p.rec == nil { + return + } + if isBasicUntyped(e.Type) { + typ := param + retry: + switch t := typ.(type) { + case *unboundFuncParam: + typ = t.tBound + goto retry + } + if !isBasicUntyped(typ) { + p.rec.UpdateUntyped(e, typ) + } + } +} + +func (p *CodeBuilder) recordUpdateUntypedBinaryOp(tok token.Token, args []*internal.Elem, tyRet types.Type) { + if p.rec == nil { + return + } + kind := binaryOpKinds[tok] + if kind == binaryOpCompare { + b0, b1 := isBasicUntyped(args[0].Type), isBasicUntyped(args[1].Type) + if b0 && !b1 { + p.rec.UpdateUntyped(args[0], args[1].Type) + } else if !b0 && b1 { + p.rec.UpdateUntyped(args[1], args[0].Type) + } + } else if tyRet != nil && !isBasicUntyped(tyRet) { + if isBasicUntyped(args[0].Type) { + p.rec.UpdateUntyped(args[0], tyRet) + } + if kind != binaryOpShift && isBasicUntyped(args[1].Type) { + p.rec.UpdateUntyped(args[1], tyRet) + } + } +} diff --git a/type_var_and_const.go b/type_var_and_const.go index 91322176..1f803874 100644 --- a/type_var_and_const.go +++ b/type_var_and_const.go @@ -328,10 +328,7 @@ func (p *ValueDecl) endInit(cb *CodeBuilder, arity int) *ValueDecl { if err := matchType(pkg, ret, typ, "assignment"); err != nil { panic(err) } - // update untyped - if cb.rec != nil && isBasicUntyped(ret.Type) { - cb.rec.UpdateUntyped(ret, typ) - } + cb.recordUpdateUntyped(ret, typ) if values != nil { // ret.Val may be changed values[i] = ret.Val } @@ -367,10 +364,7 @@ func (p *ValueDecl) endInit(cb *CodeBuilder, arity int) *ValueDecl { if values != nil { values[i] = parg.Val } - // update untyped - if pkg.cb.rec != nil && isBasicUntyped(rets[i].Type) { - pkg.cb.rec.UpdateUntyped(rets[i], retType) - } + pkg.cb.recordUpdateUntyped(rets[i], retType) if old := p.scope.Insert(types.NewVar(p.pos, pkg.Types, name, retType)); old != nil { if p.tok != token.DEFINE { oldpos := cb.fset.Position(old.Pos()) From c726e5f72d40cd82ee42bda403de28e617412071 Mon Sep 17 00:00:00 2001 From: visualfc Date: Thu, 23 Nov 2023 11:59:04 +0800 Subject: [PATCH 06/16] SliceLit/ArrayLit/MapLit: record update untyped --- ast.go | 2 +- codebuild.go | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ast.go b/ast.go index 5dc5d32d..48902828 100644 --- a/ast.go +++ b/ast.go @@ -481,7 +481,6 @@ func binaryOp(cb *CodeBuilder, tok token.Token, args []*internal.Elem) constant. if tok == token.QUO && isNormalInt(cb, args[0]) && isNormalInt(cb, args[1]) { tok = token.QUO_ASSIGN // issue #805 } - cb.recordUpdateUntypedBinaryOp(tok, args, nil) return doBinaryOp(a, tok, b) } } @@ -690,6 +689,7 @@ retry: cval = unaryOp(pkg, t.tok(), args) } else if t.isOp() { cval = binaryOp(&pkg.cb, t.tok(), args) + pkg.cb.recordUpdateUntypedBinaryOp(t.tok(), args, nil) } else if t.hasApproxType() { flags |= instrFlagApproxType } diff --git a/codebuild.go b/codebuild.go index 87a7b26c..0c961a6f 100644 --- a/codebuild.go +++ b/codebuild.go @@ -828,6 +828,8 @@ func (p *CodeBuilder) MapLit(typ types.Type, arity int, src ...ast.Node) *CodeBu pos, "cannot use %s (type %v) as type %v in map value", src, args[i+1].Type, val) } } + p.recordUpdateUntyped(args[i], key) + p.recordUpdateUntyped(args[i+1], val) } p.stk.Ret(arity, &internal.Elem{ Type: typ, Val: &ast.CompositeLit{Type: typExpr, Elts: elts}, Src: getSrc(src), @@ -876,6 +878,7 @@ func (p *CodeBuilder) indexElemExpr(args []*internal.Elem, i int) ast.Expr { return args[i+1].Val } p.toIntVal(args[i], "index which must be non-negative integer constant") + p.recordUpdateUntyped(args[i], types.Typ[types.Int]) return &ast.KeyValueExpr{Key: key, Value: args[i+1].Val} } @@ -921,6 +924,7 @@ func (p *CodeBuilder) SliceLitEx(typ types.Type, arity int, keyVal bool, src ... p.panicCodeErrorf( pos, "cannot use %s (type %v) as type %v in slice literal", src, args[i+1].Type, val) } + p.recordUpdateUntyped(arg, val) elts[i>>1] = p.indexElemExpr(args, i) } } else { @@ -956,6 +960,7 @@ func (p *CodeBuilder) SliceLitEx(typ types.Type, arity int, keyVal bool, src ... pos, "cannot use %s (type %v) as type %v in slice literal", src, arg.Type, val) } } + p.recordUpdateUntyped(arg, val) } } p.stk.Ret(arity, &internal.Elem{ @@ -1008,6 +1013,7 @@ func (p *CodeBuilder) ArrayLitEx(typ types.Type, arity int, keyVal bool, src ... p.panicCodeErrorf( pos, "cannot use %s (type %v) as type %v in array literal", src, args[i+1].Type, val) } + p.recordUpdateUntyped(args[i+1], val) elts[i>>1] = p.indexElemExpr(args, i) } } else { @@ -1028,6 +1034,7 @@ func (p *CodeBuilder) ArrayLitEx(typ types.Type, arity int, keyVal bool, src ... p.panicCodeErrorf( pos, "cannot use %s (type %v) as type %v in array literal", src, arg.Type, val) } + p.recordUpdateUntyped(arg, val) } } p.stk.Ret(arity, &internal.Elem{ @@ -2063,9 +2070,7 @@ retry: if !ComparableTo(pkg, args[0], args[1]) { return nil, errors.New("mismatched types") } - - pkg.cb.recordUpdateUntypedBinaryOp(op, args, nil) - + cb.recordUpdateUntypedBinaryOp(op, args, nil) ret = &internal.Elem{ Val: &ast.BinaryExpr{ X: checkParenExpr(args[0].Val), Op: op, From 63f0d533ebbc5048d4e12e043d0a6f8cfe4a0b39 Mon Sep 17 00:00:00 2001 From: visualfc Date: Thu, 23 Nov 2023 13:25:51 +0800 Subject: [PATCH 07/16] x --- codebuild.go | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/codebuild.go b/codebuild.go index 0c961a6f..bd0f8eff 100644 --- a/codebuild.go +++ b/codebuild.go @@ -2656,28 +2656,19 @@ func (p *CodeBuilder) InternalStack() *InternalStack { // ---------------------------------------------------------------------------- func (p *CodeBuilder) recordUpdateUntypedDefault(e *internal.Elem) { - if p.rec == nil { - return - } - if isBasicUntyped(e.Type) { + if p.rec != nil && isBasicUntyped(e.Type) { p.rec.UpdateUntyped(e, types.Default(e.Type)) } } func (p *CodeBuilder) recordUpdateUntyped(e *internal.Elem, typ types.Type) { - if p.rec == nil { - return - } - if isBasicUntyped(e.Type) && !isBasicUntyped(typ) { + if p.rec != nil && isBasicUntyped(e.Type) && !isBasicUntyped(typ) { p.rec.UpdateUntyped(e, typ) } } func (p *CodeBuilder) recordUpdateUntypedParam(e *internal.Elem, param types.Type) { - if p.rec == nil { - return - } - if isBasicUntyped(e.Type) { + if p.rec != nil && isBasicUntyped(e.Type) { typ := param retry: switch t := typ.(type) { From d524d4cbb03c9d48d427788e712f388d01a11396 Mon Sep 17 00:00:00 2001 From: visualfc Date: Thu, 23 Nov 2023 19:11:43 +0800 Subject: [PATCH 08/16] TestVarBinary --- package_test.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/package_test.go b/package_test.go index e24db31c..d78b4dac 100644 --- a/package_test.go +++ b/package_test.go @@ -3438,4 +3438,21 @@ func main() { `) } +func TestVarBinary(t *testing.T) { + pkg := newMainPackage() + pkg.CB().NewVarStart(types.Typ[types.Int], "a"). + Val(1). + EndInit(1). + NewVarStart(types.Typ[types.Int], "b"). + Val(&ast.BasicLit{Kind: token.INT, Value: "4"}). + Val(pkg.Ref("a")). + BinaryOp(token.ADD). + EndInit(1) + domTest(t, pkg, `package main + +var a int = 1 +var b int = 4 + a +`) +} + // ---------------------------------------------------------------------------- From bcb1394e6e1585f94f0a7847920c797ba5a48f55 Mon Sep 17 00:00:00 2001 From: visualfc Date: Thu, 23 Nov 2023 21:07:36 +0800 Subject: [PATCH 09/16] assign/result: record update untyped --- ast.go | 4 +++- codebuild.go | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ast.go b/ast.go index 48902828..e35730ac 100644 --- a/ast.go +++ b/ast.go @@ -1072,9 +1072,11 @@ func checkFuncResults(pkg *Package, rets []*internal.Elem, results *types.Tuple, } if n == need { for i := 0; i < need; i++ { - if err := matchType(pkg, rets[i], results.At(i).Type(), "return argument"); err != nil { + typ := results.At(i).Type() + if err := matchType(pkg, rets[i], typ, "return argument"); err != nil { panic(err) } + pkg.cb.recordUpdateUntypedParam(rets[i], typ) } return } diff --git a/codebuild.go b/codebuild.go index bd0f8eff..73e8d10d 100644 --- a/codebuild.go +++ b/codebuild.go @@ -2004,6 +2004,7 @@ func (p *CodeBuilder) doAssignWith(lhs, rhs int, src ast.Node) *CodeBuilder { lhsType = &refType{typ: bfr.typ} } checkAssignType(p.pkg, lhsType, args[lhs+i]) + p.recordUpdateUntypedParam(args[lhs+i], lhsType) stmt.Lhs[i] = args[i].Val stmt.Rhs[i] = args[lhs+i].Val if bfAssign { @@ -2675,6 +2676,8 @@ func (p *CodeBuilder) recordUpdateUntypedParam(e *internal.Elem, param types.Typ case *unboundFuncParam: typ = t.tBound goto retry + case *refType: + typ = t.typ } if !isBasicUntyped(typ) { p.rec.UpdateUntyped(e, typ) From 71ebaeee5b93438bc889b3716c5d75e9bdd480e6 Mon Sep 17 00:00:00 2001 From: visualfc Date: Thu, 23 Nov 2023 21:16:39 +0800 Subject: [PATCH 10/16] case: record update untyped --- stmt.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stmt.go b/stmt.go index 65272102..2b04dbee 100644 --- a/stmt.go +++ b/stmt.go @@ -167,11 +167,13 @@ func (p *switchStmt) Case(cb *CodeBuilder, n int, src ...ast.Node) { cb.panicCodeErrorf( pos, "cannot use %s (type %v) as type %v", src, arg.Type, types.Default(p.tag.Type)) } + cb.recordUpdateUntyped(arg, p.tag.Type) } else { // switch {...} if !types.AssignableTo(arg.Type, types.Typ[types.Bool]) && arg.Type != TyEmptyInterface { src, pos := cb.loadExpr(arg.Src) cb.panicCodeErrorf(pos, "cannot use %s (type %v) as type bool", src, arg.Type) } + cb.recordUpdateUntyped(arg, types.Typ[types.Bool]) } list[i] = arg.Val } From e674c3b7a7d027f320143a3a036884ea76202c95 Mon Sep 17 00:00:00 2001 From: visualfc Date: Thu, 23 Nov 2023 21:49:06 +0800 Subject: [PATCH 11/16] index/indexRef: record update untyped --- codebuild.go | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/codebuild.go b/codebuild.go index 73e8d10d..78f92514 100644 --- a/codebuild.go +++ b/codebuild.go @@ -1155,10 +1155,10 @@ func (p *CodeBuilder) Slice(slice3 bool, src ...ast.Node) *CodeBuilder { // a[i: exprMax = args[3].Val } - p.recordUpdateUntypedDefault(args[1]) - p.recordUpdateUntypedDefault(args[2]) + p.recordUpdateUntyped(args[1], tyInt) + p.recordUpdateUntyped(args[2], tyInt) if slice3 { - p.recordUpdateUntypedDefault(args[3]) + p.recordUpdateUntyped(args[3], tyInt) } // TODO: check type @@ -1201,6 +1201,7 @@ func (p *CodeBuilder) Index(nidx int, twoValue bool, src ...ast.Node) *CodeBuild } else { // elem = a[key] tyRet = typs[1] } + p.recordUpdateUntyped(args[1], tyInt) elem := &internal.Elem{ Val: &ast.IndexExpr{X: args[0].Val, Index: args[1].Val}, Type: tyRet, Src: srcExpr, } @@ -1219,6 +1220,7 @@ func (p *CodeBuilder) IndexRef(nidx int, src ...ast.Node) *CodeBuilder { } args := p.stk.GetArgs(2) typ := args[0].Type + p.recordUpdateUntyped(args[1], tyInt) elemRef := &internal.Elem{ Val: &ast.IndexExpr{X: args[0].Val, Index: args[1].Val}, Src: getSrc(src), @@ -2656,12 +2658,6 @@ func (p *CodeBuilder) InternalStack() *InternalStack { // ---------------------------------------------------------------------------- -func (p *CodeBuilder) recordUpdateUntypedDefault(e *internal.Elem) { - if p.rec != nil && isBasicUntyped(e.Type) { - p.rec.UpdateUntyped(e, types.Default(e.Type)) - } -} - func (p *CodeBuilder) recordUpdateUntyped(e *internal.Elem, typ types.Type) { if p.rec != nil && isBasicUntyped(e.Type) && !isBasicUntyped(typ) { p.rec.UpdateUntyped(e, typ) From 7df7a66514985de8660bf6793fb76fcc4e359d70 Mon Sep 17 00:00:00 2001 From: visualfc Date: Fri, 24 Nov 2023 07:44:57 +0800 Subject: [PATCH 12/16] send: record update untyped --- codebuild.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/codebuild.go b/codebuild.go index 78f92514..156ec00e 100644 --- a/codebuild.go +++ b/codebuild.go @@ -2189,6 +2189,9 @@ func (p *CodeBuilder) Send() *CodeBuilder { val := p.stk.Pop() ch := p.stk.Pop() // TODO: check types + if typ, ok := ch.Type.(*types.Chan); ok { + p.recordUpdateUntyped(val, typ.Elem()) + } p.emitStmt(&ast.SendStmt{Chan: ch.Val, Value: val.Val}) return p } From 3bcb238d100d648e0760657f030771f41c754b5d Mon Sep 17 00:00:00 2001 From: visualfc Date: Fri, 24 Nov 2023 09:57:07 +0800 Subject: [PATCH 13/16] record update untyped check TyEmptyInterface --- ast.go | 5 +++-- codebuild.go | 27 ++++++++++++++++----------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/ast.go b/ast.go index e35730ac..f3acd80f 100644 --- a/ast.go +++ b/ast.go @@ -1034,7 +1034,7 @@ func matchFuncArgs( if err := matchType(pkg, arg, typ, at); err != nil { return err } - pkg.cb.recordUpdateUntypedParam(arg, typ) + pkg.cb.recordUpdateUntyped(arg, typ) } return nil } @@ -1076,7 +1076,7 @@ func checkFuncResults(pkg *Package, rets []*internal.Elem, results *types.Tuple, if err := matchType(pkg, rets[i], typ, "return argument"); err != nil { panic(err) } - pkg.cb.recordUpdateUntypedParam(rets[i], typ) + pkg.cb.recordUpdateUntyped(rets[i], typ) } return } @@ -1114,6 +1114,7 @@ func matchElemType(pkg *Package, vals []*internal.Elem, elt types.Type, at inter if err := matchType(pkg, val, elt, at); err != nil { return err } + pkg.cb.recordUpdateUntyped(val, elt) } return nil } diff --git a/codebuild.go b/codebuild.go index 156ec00e..38282486 100644 --- a/codebuild.go +++ b/codebuild.go @@ -2006,7 +2006,7 @@ func (p *CodeBuilder) doAssignWith(lhs, rhs int, src ast.Node) *CodeBuilder { lhsType = &refType{typ: bfr.typ} } checkAssignType(p.pkg, lhsType, args[lhs+i]) - p.recordUpdateUntypedParam(args[lhs+i], lhsType) + p.recordUpdateUntyped(args[lhs+i], lhsType) stmt.Lhs[i] = args[i].Val stmt.Rhs[i] = args[lhs+i].Val if bfAssign { @@ -2661,13 +2661,7 @@ func (p *CodeBuilder) InternalStack() *InternalStack { // ---------------------------------------------------------------------------- -func (p *CodeBuilder) recordUpdateUntyped(e *internal.Elem, typ types.Type) { - if p.rec != nil && isBasicUntyped(e.Type) && !isBasicUntyped(typ) { - p.rec.UpdateUntyped(e, typ) - } -} - -func (p *CodeBuilder) recordUpdateUntypedParam(e *internal.Elem, param types.Type) { +func (p *CodeBuilder) recordUpdateUntyped(e *internal.Elem, param types.Type) { if p.rec != nil && isBasicUntyped(e.Type) { typ := param retry: @@ -2677,10 +2671,21 @@ func (p *CodeBuilder) recordUpdateUntypedParam(e *internal.Elem, param types.Typ goto retry case *refType: typ = t.typ + goto retry + case *types.Basic: + if (t.Info() & types.IsUntyped) != 0 { + return + } + case *types.Named: + if t.Underlying() == TyEmptyInterface { + typ = types.Default(e.Type) + } + case *types.Interface: + if t == TyEmptyInterface { + typ = types.Default(e.Type) + } } - if !isBasicUntyped(typ) { - p.rec.UpdateUntyped(e, typ) - } + p.rec.UpdateUntyped(e, typ) } } From 5355e75d63d08981f3cfabc43ca57ee23b04a36d Mon Sep 17 00:00:00 2001 From: visualfc Date: Fri, 24 Nov 2023 10:08:44 +0800 Subject: [PATCH 14/16] TestVarEmptyInterface --- package_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/package_test.go b/package_test.go index d78b4dac..26233789 100644 --- a/package_test.go +++ b/package_test.go @@ -3455,4 +3455,20 @@ var b int = 4 + a `) } +func TestVarEmptyInterface(t *testing.T) { + pkg := newMainPackage() + named := pkg.NewType("T").InitType(pkg, gox.TyEmptyInterface) + pkg.CB().NewVarStart(named, "a").Val(1).EndInit(1). + NewVarStart(gox.TyEmptyInterface, "b").Val(2).EndInit(1) + domTest(t, pkg, `package main + +type T interface { +} + +var a T = 1 +var b interface { +} = 2 +`) +} + // ---------------------------------------------------------------------------- From 8a2104238f8c870ecd2c6777d93e157d014b9a06 Mon Sep 17 00:00:00 2001 From: visualfc Date: Fri, 24 Nov 2023 10:46:39 +0800 Subject: [PATCH 15/16] x --- ast.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ast.go b/ast.go index f3acd80f..434185c8 100644 --- a/ast.go +++ b/ast.go @@ -1194,7 +1194,7 @@ func (p *MatchError) Error() string { } // TODO: use matchType to all assignable check -func matchType(pkg *Package, arg *internal.Elem, param types.Type, at interface{}) (r error) { +func matchType(pkg *Package, arg *internal.Elem, param types.Type, at interface{}) error { if debugMatch { cval := "" if arg.CVal != nil { From 033d6a1d084e883e858516e50f6f033f7868619b Mon Sep 17 00:00:00 2001 From: visualfc Date: Fri, 24 Nov 2023 12:18:08 +0800 Subject: [PATCH 16/16] record update untyped check basic --- ast.go | 7 +++++++ codebuild.go | 21 ++++++++++++++++----- package_test.go | 12 ++++++++---- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/ast.go b/ast.go index 434185c8..444fd554 100644 --- a/ast.go +++ b/ast.go @@ -182,6 +182,13 @@ func isBasicUntyped(typ types.Type) bool { return false } +func isBasicUntypedKind(typ types.Type) (bool, types.BasicKind) { + if t, ok := typ.(*types.Basic); ok { + return (t.Info() & types.IsUntyped) != 0, t.Kind() + } + return false, types.Invalid +} + func isUntyped(pkg *Package, typ types.Type) bool { switch t := typ.(type) { case *types.Basic: diff --git a/codebuild.go b/codebuild.go index 38282486..0583d7aa 100644 --- a/codebuild.go +++ b/codebuild.go @@ -2673,7 +2673,7 @@ func (p *CodeBuilder) recordUpdateUntyped(e *internal.Elem, param types.Type) { typ = t.typ goto retry case *types.Basic: - if (t.Info() & types.IsUntyped) != 0 { + if e.Type == t { return } case *types.Named: @@ -2695,17 +2695,28 @@ func (p *CodeBuilder) recordUpdateUntypedBinaryOp(tok token.Token, args []*inter } kind := binaryOpKinds[tok] if kind == binaryOpCompare { - b0, b1 := isBasicUntyped(args[0].Type), isBasicUntyped(args[1].Type) + b0, k0 := isBasicUntypedKind(args[0].Type) + b1, k1 := isBasicUntypedKind(args[1].Type) if b0 && !b1 { p.rec.UpdateUntyped(args[0], args[1].Type) } else if !b0 && b1 { p.rec.UpdateUntyped(args[1], args[0].Type) + } else if b0 && b1 && k0 != k1 { + // UntypedInt + // UntypedRune + // UntypedFloat + // UntypedComplex + if k0 < k1 { + p.rec.UpdateUntyped(args[0], args[1].Type) + } else { + p.rec.UpdateUntyped(args[1], args[0].Type) + } } - } else if tyRet != nil && !isBasicUntyped(tyRet) { - if isBasicUntyped(args[0].Type) { + } else if tyRet != nil { + if isBasicUntyped(args[0].Type) && tyRet != args[0].Type { p.rec.UpdateUntyped(args[0], tyRet) } - if kind != binaryOpShift && isBasicUntyped(args[1].Type) { + if kind != binaryOpShift && tyRet != args[1].Type { p.rec.UpdateUntyped(args[1], tyRet) } } diff --git a/package_test.go b/package_test.go index 26233789..042ba543 100644 --- a/package_test.go +++ b/package_test.go @@ -3444,14 +3444,18 @@ func TestVarBinary(t *testing.T) { Val(1). EndInit(1). NewVarStart(types.Typ[types.Int], "b"). - Val(&ast.BasicLit{Kind: token.INT, Value: "4"}). - Val(pkg.Ref("a")). - BinaryOp(token.ADD). - EndInit(1) + Val(4).Val(pkg.Ref("a")).BinaryOp(token.ADD). + EndInit(1). + NewVarStart(types.Typ[types.Bool], "c"). + Val(1).Val(1.0).BinaryOp(token.EQL).EndInit(1). + NewVarStart(types.Typ[types.Bool], "d"). + Val(1.0).Val(1).BinaryOp(token.NEQ).EndInit(1) domTest(t, pkg, `package main var a int = 1 var b int = 4 + a +var c bool = 1 == 1.0 +var d bool = 1.0 != 1 `) }