func (p *importer) param(named bool) (*types.Var, bool) { t := p.typ(nil) td, isddd := t.(*dddSlice) if isddd { t = types.NewSlice(td.elem) } var pkg *types.Package var name string if named { name = p.string() if name == "" { panic("expected named parameter") } if name != "_" { pkg = p.pkg() } if i := strings.Index(name, "·"); i > 0 { name = name[:i] // cut off gc-specific parameter numbering } } // read and discard compiler-specific info p.string() return types.NewVar(token.NoPos, pkg, name, t), isddd }
// generate generates offline constraints for the entire program. func (a *analysis) generate() { start("Constraint generation") if a.log != nil { fmt.Fprintln(a.log, "==== Generating constraints") } // Create a dummy node since we use the nodeid 0 for // non-pointerlike variables. a.addNodes(tInvalid, "(zero)") // Create the global node for panic values. a.panicNode = a.addNodes(tEface, "panic") // Create nodes and constraints for all methods of reflect.rtype. // (Shared contours are used by dynamic calls to reflect.Type // methods---typically just String().) if rtype := a.reflectRtypePtr; rtype != nil { a.genMethodsOf(rtype) } root := a.genRootCalls() if a.config.BuildCallGraph { a.result.CallGraph = callgraph.New(root.fn) } // Create nodes and constraints for all methods of all types // that are dynamically accessible via reflection or interfaces. for _, T := range a.prog.RuntimeTypes() { a.genMethodsOf(T) } // Generate constraints for functions as they become reachable // from the roots. (No constraints are generated for functions // that are dead in this analysis scope.) for len(a.genq) > 0 { cgn := a.genq[0] a.genq = a.genq[1:] a.genFunc(cgn) } // The runtime magically allocates os.Args; so should we. if os := a.prog.ImportedPackage("os"); os != nil { // In effect: os.Args = new([1]string)[:] T := types.NewSlice(types.Typ[types.String]) obj := a.addNodes(sliceToArray(T), "<command-line args>") a.endObject(obj, nil, "<command-line args>") a.addressOf(T, a.objectNode(nil, os.Var("Args")), obj) } // Discard generation state, to avoid confusion after node renumbering. a.panicNode = 0 a.globalval = nil a.localval = nil a.localobj = nil stop("Constraint generation") }
// createParams creates parameters for wrapper method fn based on its // Signature.Params, which do not include the receiver. // start is the index of the first regular parameter to use. // func createParams(fn *Function, start int) { var last *Parameter tparams := fn.Signature.Params() for i, n := start, tparams.Len(); i < n; i++ { last = fn.addParamObj(tparams.At(i)) } if fn.Signature.Variadic() { last.typ = types.NewSlice(last.typ) } }
// ArrayOrSliceType = "[" [ int ] "]" Type . func (p *parser) parseArrayOrSliceType(pkg *types.Package) types.Type { p.expect('[') if p.tok == ']' { p.next() return types.NewSlice(p.parseType(pkg)) } n := p.parseInt() p.expect(']') return types.NewArray(p.parseType(pkg), n) }
// Param = Name ["..."] Type . func (p *parser) parseParam(pkg *types.Package) (param *types.Var, isVariadic bool) { name := p.parseName() if p.tok == '.' { p.next() p.expect('.') p.expect('.') isVariadic = true } typ := p.parseType(pkg) if isVariadic { typ = types.NewSlice(typ) } param = types.NewParam(token.NoPos, pkg, name, typ) return }
// Type = // BasicType | TypeName | ArrayType | SliceType | StructType | // PointerType | FuncType | InterfaceType | MapType | ChanType | // "(" Type ")" . // // BasicType = ident . // TypeName = ExportedName . // SliceType = "[" "]" Type . // PointerType = "*" Type . // FuncType = "func" Signature . // func (p *parser) parseType(parent *types.Package) types.Type { switch p.tok { case scanner.Ident: switch p.lit { default: return p.parseBasicType() case "struct": return p.parseStructType(parent) case "func": // FuncType p.next() return p.parseSignature(nil) case "interface": return p.parseInterfaceType(parent) case "map": return p.parseMapType(parent) case "chan": return p.parseChanType(parent) } case '@': // TypeName pkg, name := p.parseExportedName() return declTypeName(pkg, name).Type() case '[': p.next() // look ahead if p.tok == ']' { // SliceType p.next() return types.NewSlice(p.parseType(parent)) } return p.parseArrayType(parent) case '*': // PointerType p.next() return types.NewPointer(p.parseType(parent)) case '<': return p.parseChanType(parent) case '(': // "(" Type ")" p.next() typ := p.parseType(parent) p.expect(')') return typ } p.errorf("expected type, got %s (%q)", scanner.TokenString(p.tok), p.lit) return nil }
func (p *importer) param(named bool) (*types.Var, bool) { t := p.typ(nil) td, isddd := t.(*dddSlice) if isddd { t = types.NewSlice(td.elem) } var name string if named { name = p.string() if name == "" { panic("expected named parameter") } } // read and discard compiler-specific info p.string() return types.NewVar(token.NoPos, nil, name, t), isddd }
// Parameter = ( identifier | "?" ) [ "..." ] Type [ string_lit ] . // func (p *parser) parseParameter() (par *types.Var, isVariadic bool) { _, name := p.parseName(nil, false) // remove gc-specific parameter numbering if i := strings.Index(name, "·"); i >= 0 { name = name[:i] } if p.tok == '.' { p.expectSpecial("...") isVariadic = true } typ := p.parseType(nil) if isVariadic { typ = types.NewSlice(typ) } // ignore argument tag (e.g. "noescape") if p.tok == scanner.String { p.next() } // TODO(gri) should we provide a package? par = types.NewVar(token.NoPos, nil, name, typ) return }
func (c *funcContext) translateConversion(expr ast.Expr, desiredType types.Type) *expression { exprType := c.p.TypeOf(expr) if types.Identical(exprType, desiredType) { return c.translateExpr(expr) } if c.p.Pkg.Path() == "reflect" { if call, isCall := expr.(*ast.CallExpr); isCall && types.Identical(c.p.TypeOf(call.Fun), types.Typ[types.UnsafePointer]) { if ptr, isPtr := desiredType.(*types.Pointer); isPtr { if named, isNamed := ptr.Elem().(*types.Named); isNamed { switch named.Obj().Name() { case "arrayType", "chanType", "funcType", "interfaceType", "mapType", "ptrType", "sliceType", "structType": return c.formatExpr("%e.kindType", call.Args[0]) // unsafe conversion default: return c.translateExpr(expr) } } } } } switch t := desiredType.Underlying().(type) { case *types.Basic: switch { case isInteger(t): basicExprType := exprType.Underlying().(*types.Basic) switch { case is64Bit(t): if !is64Bit(basicExprType) { if basicExprType.Kind() == types.Uintptr { // this might be an Object returned from reflect.Value.Pointer() return c.formatExpr("new %1s(0, %2e.constructor === Number ? %2e : 1)", c.typeName(desiredType), expr) } return c.formatExpr("new %s(0, %e)", c.typeName(desiredType), expr) } return c.formatExpr("new %1s(%2h, %2l)", c.typeName(desiredType), expr) case is64Bit(basicExprType): if !isUnsigned(t) && !isUnsigned(basicExprType) { return c.fixNumber(c.formatParenExpr("%1l + ((%1h >> 31) * 4294967296)", expr), t) } return c.fixNumber(c.formatExpr("%s.$low", c.translateExpr(expr)), t) case isFloat(basicExprType): return c.formatParenExpr("%e >> 0", expr) case types.Identical(exprType, types.Typ[types.UnsafePointer]): return c.translateExpr(expr) default: return c.fixNumber(c.translateExpr(expr), t) } case isFloat(t): if t.Kind() == types.Float32 && exprType.Underlying().(*types.Basic).Kind() == types.Float64 { return c.formatExpr("$fround(%e)", expr) } return c.formatExpr("%f", expr) case isComplex(t): return c.formatExpr("new %1s(%2r, %2i)", c.typeName(desiredType), expr) case isString(t): value := c.translateExpr(expr) switch et := exprType.Underlying().(type) { case *types.Basic: if is64Bit(et) { value = c.formatExpr("%s.$low", value) } if isNumeric(et) { return c.formatExpr("$encodeRune(%s)", value) } return value case *types.Slice: if types.Identical(et.Elem().Underlying(), types.Typ[types.Rune]) { return c.formatExpr("$runesToString(%s)", value) } return c.formatExpr("$bytesToString(%s)", value) default: panic(fmt.Sprintf("Unhandled conversion: %v\n", et)) } case t.Kind() == types.UnsafePointer: if unary, isUnary := expr.(*ast.UnaryExpr); isUnary && unary.Op == token.AND { if indexExpr, isIndexExpr := unary.X.(*ast.IndexExpr); isIndexExpr { return c.formatExpr("$sliceToArray(%s)", c.translateConversionToSlice(indexExpr.X, types.NewSlice(types.Typ[types.Uint8]))) } if ident, isIdent := unary.X.(*ast.Ident); isIdent && ident.Name == "_zero" { return c.formatExpr("new Uint8Array(0)") } } if ptr, isPtr := c.p.TypeOf(expr).(*types.Pointer); c.p.Pkg.Path() == "syscall" && isPtr { if s, isStruct := ptr.Elem().Underlying().(*types.Struct); isStruct { array := c.newVariable("_array") target := c.newVariable("_struct") c.Printf("%s = new Uint8Array(%d);", array, sizes32.Sizeof(s)) c.Delayed(func() { c.Printf("%s = %s, %s;", target, c.translateExpr(expr), c.loadStruct(array, target, s)) }) return c.formatExpr("%s", array) } } if call, ok := expr.(*ast.CallExpr); ok { if id, ok := call.Fun.(*ast.Ident); ok && id.Name == "new" { return c.formatExpr("new Uint8Array(%d)", int(sizes32.Sizeof(c.p.TypeOf(call.Args[0])))) } } } case *types.Slice: switch et := exprType.Underlying().(type) { case *types.Basic: if isString(et) { if types.Identical(t.Elem().Underlying(), types.Typ[types.Rune]) { return c.formatExpr("new %s($stringToRunes(%e))", c.typeName(desiredType), expr) } return c.formatExpr("new %s($stringToBytes(%e))", c.typeName(desiredType), expr) } case *types.Array, *types.Pointer: return c.formatExpr("new %s(%e)", c.typeName(desiredType), expr) } case *types.Pointer: switch u := t.Elem().Underlying().(type) { case *types.Array: return c.translateExpr(expr) case *types.Struct: if c.p.Pkg.Path() == "syscall" && types.Identical(exprType, types.Typ[types.UnsafePointer]) { array := c.newVariable("_array") target := c.newVariable("_struct") return c.formatExpr("(%s = %e, %s = %e, %s, %s)", array, expr, target, c.zeroValue(t.Elem()), c.loadStruct(array, target, u), target) } return c.formatExpr("$pointerOfStructConversion(%e, %s)", expr, c.typeName(t)) } if !types.Identical(exprType, types.Typ[types.UnsafePointer]) { exprTypeElem := exprType.Underlying().(*types.Pointer).Elem() ptrVar := c.newVariable("_ptr") getterConv := c.translateConversion(c.setType(&ast.StarExpr{X: c.newIdent(ptrVar, exprType)}, exprTypeElem), t.Elem()) setterConv := c.translateConversion(c.newIdent("$v", t.Elem()), exprTypeElem) return c.formatExpr("(%1s = %2e, new %3s(function() { return %4s; }, function($v) { %1s.$set(%5s); }, %1s.$target))", ptrVar, expr, c.typeName(desiredType), getterConv, setterConv) } case *types.Interface: if types.Identical(exprType, types.Typ[types.UnsafePointer]) { return c.translateExpr(expr) } } return c.translateImplicitConversionWithCloning(expr, desiredType) }
func ext۰reflect۰SliceOf(fr *frame, args []value) value { // Signature: func (t reflect.rtype) Type return makeReflectType(rtype{types.NewSlice(args[0].(iface).v.(rtype).t)}) }