1/* 2 * gomacro - A Go interpreter with Lisp-like macros 3 * 4 * Copyright (C) 2017-2019 Massimiliano Ghilardi 5 * 6 * This Source Code Form is subject to the terms of the Mozilla Public 7 * License, v. 2.0. If a copy of the MPL was not distributed with this 8 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * 11 * import.go 12 * 13 * Created on Apr 02, 2017 14 * Author Massimiliano Ghilardi 15 */ 16 17package fast 18 19import ( 20 "go/ast" 21 r "reflect" 22 "strconv" 23 "strings" 24 "unsafe" 25 26 . "github.com/cosmos72/gomacro/base" 27 "github.com/cosmos72/gomacro/base/genimport" 28 "github.com/cosmos72/gomacro/base/output" 29 "github.com/cosmos72/gomacro/base/paths" 30 "github.com/cosmos72/gomacro/base/reflect" 31 "github.com/cosmos72/gomacro/base/untyped" 32 xr "github.com/cosmos72/gomacro/xreflect" 33) 34 35// =========================== forget package ================================== 36 37// remove package 'path' from the list of known packages. 38// later attempts to import it again will trigger a recompile. 39func (cg *CompGlobals) UnloadPackage(path string) { 40 cg.Globals.UnloadPackage(path) 41 delete(cg.KnownImports, path) 42} 43 44// ========================== switch to package ================================ 45 46func (ir *Interp) ChangePackage(name, path string) { 47 if len(path) == 0 { 48 path = name 49 } else { 50 name = paths.FileName(path) 51 } 52 c := ir.Comp 53 if path == c.Path { 54 return 55 } 56 // load requested package if it exists, but do not define any binding in current one 57 newp, err := c.ImportPackageOrError("_", path) 58 if err != nil { 59 c.Debugf("%v", err) 60 } 61 oldp := ir.asImport() 62 63 c.CompGlobals.KnownImports[oldp.Path] = oldp // overwrite any cached import with same path as current Interp 64 65 trace := c.Globals.Options&OptShowPrompt != 0 66 top := &Interp{c.TopComp(), ir.env.Top()} 67 if newp != nil { 68 newp.Name = name 69 *ir = newp.asInterpreter(top) 70 if trace { 71 c.Debugf("switched to package %v", newp) 72 } 73 } else { 74 // requested package does not exist - create an empty one 75 ir.Comp = NewComp(top.Comp, nil) 76 ir.env = NewEnv(top.env, 0, 0) 77 if c.Globals.Options&OptDebugger != 0 { 78 ir.env.DebugComp = ir.Comp 79 } 80 ir.Comp.Name = name 81 ir.Comp.Path = path 82 if trace { 83 c.Debugf("switched to new package %v", path) 84 } 85 } 86 ir.env.Run.Globals.PackagePath = path 87} 88 89// convert *Interp to *Import. used to change package from 'ir' 90func (ir *Interp) asImport() *Import { 91 env := ir.env 92 env.MarkUsedByClosure() // do not try to recycle this Env 93 return &Import{ 94 CompBinds: ir.Comp.CompBinds, 95 EnvBinds: &ir.env.EnvBinds, 96 env: env, 97 } 98} 99 100// convert *Import to *Interp. used to change package to 'imp' 101func (imp *Import) asInterpreter(outer *Interp) Interp { 102 c := NewComp(outer.Comp, nil) 103 c.CompBinds = imp.CompBinds 104 env := imp.env 105 // preserve env.IP, env.Code[], env.DebugPos[] 106 if env.Outer == nil { 107 env.Outer = outer.env 108 } 109 env.Run = outer.env.Run 110 return Interp{c, env} 111} 112 113// =========================== import package ================================= 114 115// ImportPackage imports a package. Panics if the import fails. 116// If name is the empty string, it defaults to the identifier 117// specified in the package clause of the imported package 118func (ir *Interp) ImportPackage(name, path string) *Import { 119 return ir.Comp.ImportPackage(name, path) 120} 121 122// ImportPackageOrError imports a package. 123// If name is the empty string, it defaults to the identifier 124// specified in the package clause of the imported package 125func (ir *Interp) ImportPackageOrError(name, path string) (*Import, error) { 126 return ir.Comp.ImportPackageOrError(name, path) 127} 128 129// ImportPackage imports a package. Panics if the import fails. 130// Usually invoked as Comp.FileComp().ImportPackage(name, path) 131// because imports are usually top-level statements in a source file. 132// But we also support local imports, i.e. import statements inside a function or block. 133func (c *Comp) ImportPackage(name, path string) *Import { 134 imp, err := c.ImportPackageOrError(name, path) 135 if err != nil { 136 panic(err) 137 } 138 return imp 139} 140 141// ImportPackageOrError imports a package. 142// If name is the empty string, it defaults to the identifier 143// specified in the package clause of the imported package 144func (c *Comp) ImportPackageOrError(name, path string) (*Import, error) { 145 g := c.CompGlobals 146 imp := g.KnownImports[path] 147 if imp == nil { 148 pkgref, err := g.Importer.ImportPackageOrError(name, path) 149 if err != nil { 150 return nil, err 151 } 152 imp = g.NewImport(pkgref) 153 } 154 if name == "." { 155 c.declDotImport0(imp) 156 } else if name != "_" { 157 // https://golang.org/ref/spec#Package_clause states: 158 // If the PackageName is omitted, it defaults to the identifier 159 // specified in the package clause of the imported package 160 if len(name) == 0 { 161 name = imp.Name 162 } 163 c.declImport0(name, imp) 164 } 165 g.KnownImports[path] = imp 166 return imp, nil 167} 168 169// Import compiles an import statement 170func (c *Comp) Import(node ast.Spec) { 171 switch node := node.(type) { 172 case *ast.ImportSpec: 173 str := node.Path.Value 174 path, err := strconv.Unquote(str) 175 if err != nil { 176 c.Errorf("error unescaping import path %q: %v", str, err) 177 } 178 path = c.sanitizeImportPath(path) 179 var name string 180 if node.Name != nil { 181 name = node.Name.Name 182 } 183 // yes, we support local imports 184 // i.e. a function or block can import packages 185 c.ImportPackage(name, path) 186 default: 187 c.Errorf("unimplemented import: %v", node) 188 } 189} 190 191func (g *CompGlobals) sanitizeImportPath(path string) string { 192 path = strings.Replace(path, "\\", "/", -1) 193 l := len(path) 194 if path == ".." || l >= 3 && (path[:3] == "../" || path[l-3:] == "/..") || strings.Contains(path, "/../") { 195 g.Errorf("invalid import %q: contains \"..\"", path) 196 } 197 if path == "." || l >= 2 && (path[:2] == "./" || path[l-2:] == "/.") || strings.Contains(path, "/./") { 198 g.Errorf("invalid import %q: contains \".\"", path) 199 } 200 return path 201} 202 203// declDotImport0 compiles an import declaration. 204// Note: does not loads proxies, use ImportPackage for that 205func (c *Comp) declImport0(name string, imp *Import) { 206 // treat imported package as a constant, 207 // because to compile code we need the declarations it contains: 208 // importing them at runtime would be too late. 209 bind := c.NewBind(name, ConstBind, c.TypeOfPtrImport()) 210 bind.Value = imp // Comp.Binds[] is a map[string]*Bind => changes to *Bind propagate to the map 211} 212 213// declDotImport0 compiles an import . "path" declaration, i.e. a dot-import. 214// Note: does not loads proxies, use ImportPackage for that 215func (c *Comp) declDotImport0(imp *Import) { 216 // Note 2: looking at the difference between the above Comp.declImport0() and this ugly monster, 217 // shows one more reason why dot-imports are dirty and discouraged. 218 if c.Types == nil { 219 c.Types = make(map[string]xr.Type) 220 } 221 for name, typ := range imp.Types { 222 if t, exists := c.Types[name]; exists { 223 c.Warnf("redefined type: %v", t) 224 } 225 c.Types[name] = typ 226 } 227 228 var indexv, cindexv []int // mapping between Import.Vals[index] and Env.Vals[cindex] 229 230 var funv []func(*Env) r.Value 231 var findexv []int 232 233 for name, bind := range imp.Binds { 234 // use c.CompBinds.NewBind() to prevent optimization VarBind -> IntBind 235 // also, if class == IntBind, we must preserve the address of impenv.Ints[idx] 236 // thus we must convert it into a VarBind (argh!) 237 class := bind.Desc.Class() 238 if class == IntBind { 239 class = VarBind 240 } 241 cbind := c.CompBinds.NewBind(&c.Output, name, class, bind.Type) 242 cidx := cbind.Desc.Index() 243 switch bind.Desc.Class() { 244 case ConstBind: 245 cbind.Value = bind.Value 246 case IntBind: 247 if cidx == NoIndex { 248 continue 249 } 250 // this is painful. and slow 251 fun := imp.intPlace(c, bind, PlaceSettable).Fun 252 funv = append(funv, fun) 253 findexv = append(findexv, cidx) 254 default: 255 if cidx == NoIndex { 256 continue 257 } 258 indexv = append(indexv, bind.Desc.Index()) 259 cindexv = append(cindexv, cidx) 260 } 261 } 262 if len(indexv) != 0 || len(funv) != 0 { 263 impvals := imp.Vals 264 c.append(func(env *Env) (Stmt, *Env) { 265 for i, index := range indexv { 266 env.Vals[cindexv[i]] = impvals[index] 267 } 268 for i, fun := range funv { 269 env.Vals[findexv[i]] = fun(nil) // fun(env) is unnecessary 270 } 271 env.IP++ 272 return env.Code[env.IP], env 273 }) 274 } 275} 276 277func (g *CompGlobals) NewImport(pkgref *genimport.PackageRef) *Import { 278 env := &Env{ 279 UsedByClosure: true, // do not try to recycle this Env 280 } 281 imp := &Import{ 282 EnvBinds: &env.EnvBinds, 283 env: env, 284 } 285 if pkgref != nil { 286 imp.Name = pkgref.Name 287 imp.Path = pkgref.Path 288 imp.loadTypes(g, pkgref) 289 imp.loadBinds(g, pkgref) 290 g.loadProxies(pkgref.Proxies, imp.Types) 291 } 292 return imp 293} 294 295func (imp *Import) loadBinds(g *CompGlobals, pkgref *genimport.PackageRef) { 296 vals := make([]r.Value, len(pkgref.Binds)) 297 untypeds := pkgref.Untypeds 298 o := &g.Output 299 for name, val := range pkgref.Binds { 300 if untyped, ok := untypeds[name]; ok { 301 untypedlit, typ := g.parseUntyped(untyped) 302 if typ != nil { 303 bind := imp.CompBinds.NewBind(o, name, ConstBind, typ) 304 bind.Value = untypedlit 305 continue 306 } 307 } 308 k := val.Kind() 309 class := FuncBind 310 // distinguish typed constants, variables and functions 311 if val.IsValid() && val.CanAddr() && val.CanSet() { 312 class = VarBind 313 } else if k == r.Invalid || (reflect.IsOptimizedKind(k) && val.CanInterface()) { 314 class = ConstBind 315 } 316 typ := g.Universe.FromReflectType(val.Type()) 317 bind := imp.CompBinds.NewBind(o, name, class, typ) 318 if class == ConstBind && k != r.Invalid { 319 bind.Value = val.Interface() 320 } 321 idx := bind.Desc.Index() 322 if idx == NoIndex { 323 continue 324 } 325 if len(vals) <= idx { 326 tmp := make([]r.Value, idx*2) 327 copy(tmp, vals) 328 vals = tmp 329 } 330 vals[idx] = val 331 } 332 imp.Vals = vals 333} 334 335func (g *CompGlobals) parseUntyped(untypedstr string) (UntypedLit, xr.Type) { 336 kind, value := untyped.Unmarshal(untypedstr) 337 if kind == untyped.None { 338 return UntypedLit{}, nil 339 } 340 lit := untyped.MakeLit(kind, value, &g.Universe.BasicTypes) 341 return lit, g.TypeOfUntypedLit() 342} 343 344func (imp *Import) loadTypes(g *CompGlobals, pkgref *genimport.PackageRef) { 345 v := g.Universe 346 types := make(map[string]xr.Type) 347 wrappers := pkgref.Wrappers 348 for name, rtype := range pkgref.Types { 349 // Universe.FromReflectType uses cached *types.Package if possible 350 t := v.FromReflectType(rtype) 351 if twrappers := wrappers[name]; len(twrappers) != 0 { 352 t.RemoveMethods(twrappers, "") 353 } 354 types[name] = t 355 } 356 imp.Types = types 357} 358 359// loadProxies adds to thread-global maps the proxies found in import 360func (g *CompGlobals) loadProxies(proxies map[string]r.Type, xtypes map[string]xr.Type) { 361 for name, proxy := range proxies { 362 xtype := xtypes[name] 363 if xtype == nil { 364 g.Warnf("import %q: type not found for proxy <%v>", proxy.PkgPath(), proxy) 365 continue 366 } 367 if xtype.Kind() != r.Interface { 368 g.Warnf("import %q: type for proxy <%v> is not an interface: %v", proxy.PkgPath(), proxy, xtype) 369 continue 370 } 371 rtype := xtype.ReflectType() 372 g.interf2proxy[rtype] = proxy 373 g.proxy2interf[proxy] = xtype 374 } 375} 376 377// ======================== use package symbols =============================== 378 379// selectorPlace compiles pkgname.varname returning a settable and/or addressable Place 380func (imp *Import) selectorPlace(c *Comp, name string, opt PlaceOption) *Place { 381 bind, ok := imp.Binds[name] 382 if !ok { 383 c.Errorf("package %v %q has no symbol %s", imp.Name, imp.Path, name) 384 } 385 class := bind.Desc.Class() 386 if bind.Desc.Index() != NoIndex { 387 switch class { 388 case IntBind: 389 return imp.intPlace(c, bind, opt) 390 case VarBind: 391 // optimization: read imp.Vals[] at compile time: 392 // val remains valid even if imp.Vals[] is reallocated 393 val := imp.Vals[bind.Desc.Index()] 394 // a settable reflect.Value is always addressable. 395 // the converse is not guaranteed: unexported fields can be addressed but not set. 396 // see implementation of reflect.Value.CanAddr() and reflect.Value.CanSet() for details 397 if val.IsValid() && val.CanAddr() && val.CanSet() { 398 return &Place{ 399 Var: Var{Type: bind.Type}, 400 Fun: func(*Env) r.Value { 401 return val 402 }, 403 Addr: func(*Env) r.Value { 404 return val.Addr() 405 }, 406 } 407 } 408 } 409 } 410 c.Errorf("%v %v %v.%v", opt, class, bind.Type.Kind(), imp.Name, name) 411 return nil 412} 413 414// selector compiles foo.bar where 'foo' is an imported package 415func (imp *Import) selector(name string, st *output.Stringer) *Expr { 416 bind, ok := imp.Binds[name] 417 if !ok { 418 st.Errorf("package %v %q has no symbol %s", imp.Name, imp.Path, name) 419 } 420 switch bind.Desc.Class() { 421 case ConstBind: 422 return exprLit(bind.Lit, bind.AsSymbol(0)) 423 case FuncBind, VarBind: 424 return imp.symbol(bind, st) 425 case IntBind: 426 return imp.intSymbol(bind, st) 427 default: 428 st.Errorf("package symbol %s.%s has unknown class %s", imp.Name, name, bind.Desc.Class()) 429 return nil 430 } 431} 432 433// create an expression that will return the value of imported variable described by bind. 434// 435// mandatory optimization: for basic kinds, unwrap reflect.Value 436func (imp *Import) symbol(bind *Bind, st *output.Stringer) *Expr { 437 idx := bind.Desc.Index() 438 if idx == NoIndex { 439 st.Errorf("undefined identifier %s._", imp.Name) 440 } 441 // optimization: read imp.Vals[] at compile time: 442 // v remains valid even if imp.Vals[] is reallocated 443 v := imp.Vals[idx] 444 t := bind.Type 445 if !v.IsValid() { 446 return exprValue(t, xr.Zero(t).Interface()) 447 } 448 var fun I 449 switch t.Kind() { 450 case r.Bool: 451 fun = func(*Env) bool { 452 return v.Bool() 453 } 454 case r.Int: 455 fun = func(*Env) int { 456 return int(v.Int()) 457 } 458 case r.Int8: 459 fun = func(*Env) int8 { 460 return int8(v.Int()) 461 } 462 case r.Int16: 463 fun = func(*Env) int16 { 464 return int16(v.Int()) 465 } 466 case r.Int32: 467 fun = func(*Env) int32 { 468 return int32(v.Int()) 469 } 470 case r.Int64: 471 fun = func(*Env) int64 { 472 return v.Int() 473 } 474 case r.Uint: 475 fun = func(*Env) uint { 476 return uint(v.Uint()) 477 } 478 case r.Uint8: 479 fun = func(*Env) uint8 { 480 return uint8(v.Uint()) 481 } 482 case r.Uint16: 483 fun = func(*Env) uint16 { 484 return uint16(v.Uint()) 485 } 486 case r.Uint32: 487 fun = func(*Env) uint32 { 488 return uint32(v.Uint()) 489 } 490 case r.Uint64: 491 fun = func(*Env) uint64 { 492 return v.Uint() 493 } 494 case r.Uintptr: 495 fun = func(*Env) uintptr { 496 return uintptr(v.Uint()) 497 } 498 case r.Float32: 499 fun = func(*Env) float32 { 500 return float32(v.Float()) 501 } 502 case r.Float64: 503 fun = func(*Env) float64 { 504 return v.Float() 505 } 506 case r.Complex64: 507 fun = func(*Env) complex64 { 508 return complex64(v.Complex()) 509 } 510 case r.Complex128: 511 fun = func(*Env) complex128 { 512 return v.Complex() 513 } 514 case r.String: 515 fun = func(*Env) string { 516 return v.String() 517 } 518 default: 519 fun = func(*Env) r.Value { 520 return v 521 } 522 } 523 // v is an imported variable. do NOT store its value in *Expr, 524 // because that's how constants are represented: 525 // fast interpreter will then (incorrectly) perform constant propagation. 526 return exprFun(t, fun) 527} 528 529// create an expression that will return the value of imported variable described by bind. 530// 531// mandatory optimization: for basic kinds, do not wrap in reflect.Value 532func (imp *Import) intSymbol(bind *Bind, st *output.Stringer) *Expr { 533 idx := bind.Desc.Index() 534 if idx == NoIndex { 535 st.Errorf("undefined identifier %s._", imp.Name) 536 } 537 t := bind.Type 538 env := imp.env 539 var fun I 540 switch t.Kind() { 541 case r.Bool: 542 fun = func(*Env) bool { 543 return *(*bool)(unsafe.Pointer(&env.Ints[idx])) 544 } 545 case r.Int: 546 fun = func(*Env) int { 547 return *(*int)(unsafe.Pointer(&env.Ints[idx])) 548 } 549 case r.Int8: 550 fun = func(*Env) int8 { 551 return *(*int8)(unsafe.Pointer(&env.Ints[idx])) 552 } 553 case r.Int16: 554 fun = func(*Env) int16 { 555 return *(*int16)(unsafe.Pointer(&env.Ints[idx])) 556 } 557 case r.Int32: 558 fun = func(*Env) int32 { 559 return *(*int32)(unsafe.Pointer(&env.Ints[idx])) 560 } 561 case r.Int64: 562 fun = func(*Env) int64 { 563 return *(*int64)(unsafe.Pointer(&env.Ints[idx])) 564 } 565 case r.Uint: 566 fun = func(*Env) uint { 567 return *(*uint)(unsafe.Pointer(&env.Ints[idx])) 568 } 569 case r.Uint8: 570 fun = func(*Env) uint8 { 571 return *(*uint8)(unsafe.Pointer(&env.Ints[idx])) 572 } 573 case r.Uint16: 574 fun = func(*Env) uint16 { 575 return *(*uint16)(unsafe.Pointer(&env.Ints[idx])) 576 } 577 case r.Uint32: 578 fun = func(*Env) uint32 { 579 return *(*uint32)(unsafe.Pointer(&env.Ints[idx])) 580 } 581 case r.Uint64: 582 fun = func(*Env) uint64 { 583 return env.Ints[idx] 584 } 585 case r.Uintptr: 586 fun = func(*Env) uintptr { 587 return *(*uintptr)(unsafe.Pointer(&env.Ints[idx])) 588 } 589 case r.Float32: 590 fun = func(*Env) float32 { 591 return *(*float32)(unsafe.Pointer(&env.Ints[idx])) 592 } 593 case r.Float64: 594 fun = func(*Env) float64 { 595 return *(*float64)(unsafe.Pointer(&env.Ints[idx])) 596 } 597 case r.Complex64: 598 fun = func(*Env) complex64 { 599 return *(*complex64)(unsafe.Pointer(&env.Ints[idx])) 600 } 601 case r.Complex128: 602 fun = func(*Env) complex128 { 603 return *(*complex128)(unsafe.Pointer(&env.Ints[idx])) 604 } 605 default: 606 st.Errorf("unsupported symbol type, cannot use for optimized read: %v %v.%v <%v>", 607 bind.Desc.Class(), imp.Name, bind.Name, bind.Type) 608 return nil 609 } 610 // Do NOT store env.Ints[idx] into *Expr, because that's how constants are represented: 611 // fast interpreter will then (incorrectly) perform constant propagation. 612 return exprFun(t, fun) 613} 614 615// return a Place representing the imported variable described by bind. 616// 617// mandatory optimization: for basic kinds, do not wrap in reflect.Value 618func (imp *Import) intPlace(c *Comp, bind *Bind, opt PlaceOption) *Place { 619 idx := bind.Desc.Index() 620 if idx == NoIndex { 621 c.Errorf("%v %v %v.%v", opt, bind.Desc.Class(), imp.Name, bind.Name) 622 } 623 t := bind.Type 624 var addr func(*Env) r.Value 625 impenv := imp.env 626 switch t.Kind() { 627 case r.Bool: 628 addr = func(env *Env) r.Value { 629 return r.ValueOf((*bool)(unsafe.Pointer(&impenv.Ints[idx]))) 630 } 631 case r.Int: 632 addr = func(env *Env) r.Value { 633 return r.ValueOf((*int)(unsafe.Pointer(&impenv.Ints[idx]))) 634 } 635 case r.Int8: 636 addr = func(env *Env) r.Value { 637 return r.ValueOf((*int8)(unsafe.Pointer(&impenv.Ints[idx]))) 638 } 639 case r.Int16: 640 addr = func(env *Env) r.Value { 641 return r.ValueOf((*int16)(unsafe.Pointer(&impenv.Ints[idx]))) 642 } 643 case r.Int32: 644 addr = func(env *Env) r.Value { 645 return r.ValueOf((*int32)(unsafe.Pointer(&impenv.Ints[idx]))) 646 } 647 case r.Int64: 648 addr = func(env *Env) r.Value { 649 return r.ValueOf((*int64)(unsafe.Pointer(&impenv.Ints[idx]))) 650 } 651 case r.Uint: 652 addr = func(env *Env) r.Value { 653 return r.ValueOf((*uint)(unsafe.Pointer(&impenv.Ints[idx]))) 654 } 655 case r.Uint8: 656 addr = func(env *Env) r.Value { 657 return r.ValueOf((*uint8)(unsafe.Pointer(&impenv.Ints[idx]))) 658 } 659 case r.Uint16: 660 addr = func(env *Env) r.Value { 661 return r.ValueOf((*uint16)(unsafe.Pointer(&impenv.Ints[idx]))) 662 } 663 case r.Uint32: 664 addr = func(env *Env) r.Value { 665 return r.ValueOf((*uint32)(unsafe.Pointer(&impenv.Ints[idx]))) 666 } 667 case r.Uint64: 668 addr = func(env *Env) r.Value { 669 return r.ValueOf(&impenv.Ints[idx]) 670 } 671 case r.Uintptr: 672 addr = func(env *Env) r.Value { 673 return r.ValueOf((*uintptr)(unsafe.Pointer(&impenv.Ints[idx]))) 674 } 675 case r.Float32: 676 addr = func(env *Env) r.Value { 677 return r.ValueOf((*float32)(unsafe.Pointer(&impenv.Ints[idx]))) 678 } 679 case r.Float64: 680 addr = func(env *Env) r.Value { 681 return r.ValueOf((*float64)(unsafe.Pointer(&impenv.Ints[idx]))) 682 } 683 case r.Complex64: 684 addr = func(env *Env) r.Value { 685 return r.ValueOf((*complex64)(unsafe.Pointer(&impenv.Ints[idx]))) 686 } 687 case r.Complex128: 688 addr = func(env *Env) r.Value { 689 return r.ValueOf((*complex128)(unsafe.Pointer(&impenv.Ints[idx]))) 690 } 691 default: 692 c.Errorf("%s unsupported variable type <%v>: %s %s.%s", 693 opt, t, bind.Desc.Class(), imp.Name, bind.Name) 694 return nil 695 } 696 return &Place{ 697 Var: Var{Type: bind.Type, Name: bind.Name}, 698 Fun: func(env *Env) r.Value { 699 return addr(env).Elem() 700 }, 701 Addr: addr, 702 } 703} 704