1// Copyright 2013 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// This file implements type-checking of identifiers and type expressions. 6 7package types 8 9import ( 10 "go/ast" 11 "go/constant" 12 "go/token" 13 "sort" 14 "strconv" 15) 16 17// ident type-checks identifier e and initializes x with the value or type of e. 18// If an error occurred, x.mode is set to invalid. 19// For the meaning of def, see Checker.definedType, below. 20// If wantType is set, the identifier e is expected to denote a type. 21// 22func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, wantType bool) { 23 x.mode = invalid 24 x.expr = e 25 26 // Note that we cannot use check.lookup here because the returned scope 27 // may be different from obj.Parent(). See also Scope.LookupParent doc. 28 scope, obj := check.scope.LookupParent(e.Name, check.pos) 29 if obj == nil { 30 if e.Name == "_" { 31 check.errorf(e, _InvalidBlank, "cannot use _ as value or type") 32 } else { 33 check.errorf(e, _UndeclaredName, "undeclared name: %s", e.Name) 34 } 35 return 36 } 37 check.recordUse(e, obj) 38 39 // Type-check the object. 40 // Only call Checker.objDecl if the object doesn't have a type yet 41 // (in which case we must actually determine it) or the object is a 42 // TypeName and we also want a type (in which case we might detect 43 // a cycle which needs to be reported). Otherwise we can skip the 44 // call and avoid a possible cycle error in favor of the more 45 // informative "not a type/value" error that this function's caller 46 // will issue (see issue #25790). 47 typ := obj.Type() 48 if _, gotType := obj.(*TypeName); typ == nil || gotType && wantType { 49 check.objDecl(obj, def) 50 typ = obj.Type() // type must have been assigned by Checker.objDecl 51 } 52 assert(typ != nil) 53 54 // The object may be dot-imported: If so, remove its package from 55 // the map of unused dot imports for the respective file scope. 56 // (This code is only needed for dot-imports. Without them, 57 // we only have to mark variables, see *Var case below). 58 if pkg := obj.Pkg(); pkg != check.pkg && pkg != nil { 59 delete(check.unusedDotImports[scope], pkg) 60 } 61 62 switch obj := obj.(type) { 63 case *PkgName: 64 check.errorf(e, _InvalidPkgUse, "use of package %s not in selector", obj.name) 65 return 66 67 case *Const: 68 check.addDeclDep(obj) 69 if typ == Typ[Invalid] { 70 return 71 } 72 if obj == universeIota { 73 if check.iota == nil { 74 check.errorf(e, _InvalidIota, "cannot use iota outside constant declaration") 75 return 76 } 77 x.val = check.iota 78 } else { 79 x.val = obj.val 80 } 81 assert(x.val != nil) 82 x.mode = constant_ 83 84 case *TypeName: 85 x.mode = typexpr 86 87 case *Var: 88 // It's ok to mark non-local variables, but ignore variables 89 // from other packages to avoid potential race conditions with 90 // dot-imported variables. 91 if obj.pkg == check.pkg { 92 obj.used = true 93 } 94 check.addDeclDep(obj) 95 if typ == Typ[Invalid] { 96 return 97 } 98 x.mode = variable 99 100 case *Func: 101 check.addDeclDep(obj) 102 x.mode = value 103 104 case *Builtin: 105 x.id = obj.id 106 x.mode = builtin 107 108 case *Nil: 109 x.mode = value 110 111 default: 112 unreachable() 113 } 114 115 x.typ = typ 116} 117 118// typ type-checks the type expression e and returns its type, or Typ[Invalid]. 119func (check *Checker) typ(e ast.Expr) Type { 120 return check.definedType(e, nil) 121} 122 123// definedType is like typ but also accepts a type name def. 124// If def != nil, e is the type specification for the defined type def, declared 125// in a type declaration, and def.underlying will be set to the type of e before 126// any components of e are type-checked. 127// 128func (check *Checker) definedType(e ast.Expr, def *Named) (T Type) { 129 if trace { 130 check.trace(e.Pos(), "%s", e) 131 check.indent++ 132 defer func() { 133 check.indent-- 134 check.trace(e.Pos(), "=> %s", T) 135 }() 136 } 137 138 T = check.typInternal(e, def) 139 assert(isTyped(T)) 140 check.recordTypeAndValue(e, typexpr, T, nil) 141 142 return 143} 144 145// funcType type-checks a function or method type. 146func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) { 147 scope := NewScope(check.scope, token.NoPos, token.NoPos, "function") 148 scope.isFunc = true 149 check.recordScope(ftyp, scope) 150 151 recvList, _ := check.collectParams(scope, recvPar, false) 152 params, variadic := check.collectParams(scope, ftyp.Params, true) 153 results, _ := check.collectParams(scope, ftyp.Results, false) 154 155 if recvPar != nil { 156 // recv parameter list present (may be empty) 157 // spec: "The receiver is specified via an extra parameter section preceding the 158 // method name. That parameter section must declare a single parameter, the receiver." 159 var recv *Var 160 switch len(recvList) { 161 case 0: 162 check.error(recvPar, _BadRecv, "method is missing receiver") 163 recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below 164 default: 165 // more than one receiver 166 check.error(recvList[len(recvList)-1], _BadRecv, "method must have exactly one receiver") 167 fallthrough // continue with first receiver 168 case 1: 169 recv = recvList[0] 170 } 171 // spec: "The receiver type must be of the form T or *T where T is a type name." 172 // (ignore invalid types - error was reported before) 173 if t, _ := deref(recv.typ); t != Typ[Invalid] { 174 var err string 175 if T, _ := t.(*Named); T != nil { 176 // spec: "The type denoted by T is called the receiver base type; it must not 177 // be a pointer or interface type and it must be declared in the same package 178 // as the method." 179 if T.obj.pkg != check.pkg { 180 err = "type not defined in this package" 181 } else { 182 // TODO(gri) This is not correct if the underlying type is unknown yet. 183 switch u := T.underlying.(type) { 184 case *Basic: 185 // unsafe.Pointer is treated like a regular pointer 186 if u.kind == UnsafePointer { 187 err = "unsafe.Pointer" 188 } 189 case *Pointer, *Interface: 190 err = "pointer or interface type" 191 } 192 } 193 } else { 194 err = "basic or unnamed type" 195 } 196 if err != "" { 197 check.errorf(recv, _InvalidRecv, "invalid receiver %s (%s)", recv.typ, err) 198 // ok to continue 199 } 200 } 201 sig.recv = recv 202 } 203 204 sig.scope = scope 205 sig.params = NewTuple(params...) 206 sig.results = NewTuple(results...) 207 sig.variadic = variadic 208} 209 210// typInternal drives type checking of types. 211// Must only be called by definedType. 212// 213func (check *Checker) typInternal(e ast.Expr, def *Named) Type { 214 switch e := e.(type) { 215 case *ast.BadExpr: 216 // ignore - error reported before 217 218 case *ast.Ident: 219 var x operand 220 check.ident(&x, e, def, true) 221 222 switch x.mode { 223 case typexpr: 224 typ := x.typ 225 def.setUnderlying(typ) 226 return typ 227 case invalid: 228 // ignore - error reported before 229 case novalue: 230 check.errorf(&x, _NotAType, "%s used as type", &x) 231 default: 232 check.errorf(&x, _NotAType, "%s is not a type", &x) 233 } 234 235 case *ast.SelectorExpr: 236 var x operand 237 check.selector(&x, e) 238 239 switch x.mode { 240 case typexpr: 241 typ := x.typ 242 def.setUnderlying(typ) 243 return typ 244 case invalid: 245 // ignore - error reported before 246 case novalue: 247 check.errorf(&x, _NotAType, "%s used as type", &x) 248 default: 249 check.errorf(&x, _NotAType, "%s is not a type", &x) 250 } 251 252 case *ast.ParenExpr: 253 return check.definedType(e.X, def) 254 255 case *ast.ArrayType: 256 if e.Len != nil { 257 typ := new(Array) 258 def.setUnderlying(typ) 259 typ.len = check.arrayLength(e.Len) 260 typ.elem = check.typ(e.Elt) 261 return typ 262 263 } else { 264 typ := new(Slice) 265 def.setUnderlying(typ) 266 typ.elem = check.typ(e.Elt) 267 return typ 268 } 269 270 case *ast.StructType: 271 typ := new(Struct) 272 def.setUnderlying(typ) 273 check.structType(typ, e) 274 return typ 275 276 case *ast.StarExpr: 277 typ := new(Pointer) 278 def.setUnderlying(typ) 279 typ.base = check.typ(e.X) 280 return typ 281 282 case *ast.FuncType: 283 typ := new(Signature) 284 def.setUnderlying(typ) 285 check.funcType(typ, nil, e) 286 return typ 287 288 case *ast.InterfaceType: 289 typ := new(Interface) 290 def.setUnderlying(typ) 291 check.interfaceType(typ, e, def) 292 return typ 293 294 case *ast.MapType: 295 typ := new(Map) 296 def.setUnderlying(typ) 297 298 typ.key = check.typ(e.Key) 299 typ.elem = check.typ(e.Value) 300 301 // spec: "The comparison operators == and != must be fully defined 302 // for operands of the key type; thus the key type must not be a 303 // function, map, or slice." 304 // 305 // Delay this check because it requires fully setup types; 306 // it is safe to continue in any case (was issue 6667). 307 check.atEnd(func() { 308 if !Comparable(typ.key) { 309 check.errorf(e.Key, _IncomparableMapKey, "incomparable map key type %s", typ.key) 310 } 311 }) 312 313 return typ 314 315 case *ast.ChanType: 316 typ := new(Chan) 317 def.setUnderlying(typ) 318 319 dir := SendRecv 320 switch e.Dir { 321 case ast.SEND | ast.RECV: 322 // nothing to do 323 case ast.SEND: 324 dir = SendOnly 325 case ast.RECV: 326 dir = RecvOnly 327 default: 328 check.invalidAST(e, "unknown channel direction %d", e.Dir) 329 // ok to continue 330 } 331 332 typ.dir = dir 333 typ.elem = check.typ(e.Value) 334 return typ 335 336 default: 337 check.errorf(e, _NotAType, "%s is not a type", e) 338 } 339 340 typ := Typ[Invalid] 341 def.setUnderlying(typ) 342 return typ 343} 344 345// typeOrNil type-checks the type expression (or nil value) e 346// and returns the typ of e, or nil. 347// If e is neither a type nor nil, typOrNil returns Typ[Invalid]. 348// 349func (check *Checker) typOrNil(e ast.Expr) Type { 350 var x operand 351 check.rawExpr(&x, e, nil) 352 switch x.mode { 353 case invalid: 354 // ignore - error reported before 355 case novalue: 356 check.errorf(&x, _NotAType, "%s used as type", &x) 357 case typexpr: 358 return x.typ 359 case value: 360 if x.isNil() { 361 return nil 362 } 363 fallthrough 364 default: 365 check.errorf(&x, _NotAType, "%s is not a type", &x) 366 } 367 return Typ[Invalid] 368} 369 370// arrayLength type-checks the array length expression e 371// and returns the constant length >= 0, or a value < 0 372// to indicate an error (and thus an unknown length). 373func (check *Checker) arrayLength(e ast.Expr) int64 { 374 var x operand 375 check.expr(&x, e) 376 if x.mode != constant_ { 377 if x.mode != invalid { 378 check.errorf(&x, _InvalidArrayLen, "array length %s must be constant", &x) 379 } 380 return -1 381 } 382 if isUntyped(x.typ) || isInteger(x.typ) { 383 if val := constant.ToInt(x.val); val.Kind() == constant.Int { 384 if representableConst(val, check, Typ[Int], nil) { 385 if n, ok := constant.Int64Val(val); ok && n >= 0 { 386 return n 387 } 388 check.errorf(&x, _InvalidArrayLen, "invalid array length %s", &x) 389 return -1 390 } 391 } 392 } 393 check.errorf(&x, _InvalidArrayLen, "array length %s must be integer", &x) 394 return -1 395} 396 397func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, variadicOk bool) (params []*Var, variadic bool) { 398 if list == nil { 399 return 400 } 401 402 var named, anonymous bool 403 for i, field := range list.List { 404 ftype := field.Type 405 if t, _ := ftype.(*ast.Ellipsis); t != nil { 406 ftype = t.Elt 407 if variadicOk && i == len(list.List)-1 && len(field.Names) <= 1 { 408 variadic = true 409 } else { 410 check.softErrorf(t, _MisplacedDotDotDot, "can only use ... with final parameter in list") 411 // ignore ... and continue 412 } 413 } 414 typ := check.typ(ftype) 415 // The parser ensures that f.Tag is nil and we don't 416 // care if a constructed AST contains a non-nil tag. 417 if len(field.Names) > 0 { 418 // named parameter 419 for _, name := range field.Names { 420 if name.Name == "" { 421 check.invalidAST(name, "anonymous parameter") 422 // ok to continue 423 } 424 par := NewParam(name.Pos(), check.pkg, name.Name, typ) 425 check.declare(scope, name, par, scope.pos) 426 params = append(params, par) 427 } 428 named = true 429 } else { 430 // anonymous parameter 431 par := NewParam(ftype.Pos(), check.pkg, "", typ) 432 check.recordImplicit(field, par) 433 params = append(params, par) 434 anonymous = true 435 } 436 } 437 438 if named && anonymous { 439 check.invalidAST(list, "list contains both named and anonymous parameters") 440 // ok to continue 441 } 442 443 // For a variadic function, change the last parameter's type from T to []T. 444 // Since we type-checked T rather than ...T, we also need to retro-actively 445 // record the type for ...T. 446 if variadic { 447 last := params[len(params)-1] 448 last.typ = &Slice{elem: last.typ} 449 check.recordTypeAndValue(list.List[len(list.List)-1].Type, typexpr, last.typ, nil) 450 } 451 452 return 453} 454 455func (check *Checker) declareInSet(oset *objset, pos token.Pos, obj Object) bool { 456 if alt := oset.insert(obj); alt != nil { 457 check.errorf(atPos(pos), _DuplicateDecl, "%s redeclared", obj.Name()) 458 check.reportAltDecl(alt) 459 return false 460 } 461 return true 462} 463 464func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, def *Named) { 465 for _, f := range iface.Methods.List { 466 if len(f.Names) > 0 { 467 // We have a method with name f.Names[0]. 468 // (The parser ensures that there's only one method 469 // and we don't care if a constructed AST has more.) 470 name := f.Names[0] 471 if name.Name == "_" { 472 check.errorf(name, _BlankIfaceMethod, "invalid method name _") 473 continue // ignore 474 } 475 476 typ := check.typ(f.Type) 477 sig, _ := typ.(*Signature) 478 if sig == nil { 479 if typ != Typ[Invalid] { 480 check.invalidAST(f.Type, "%s is not a method signature", typ) 481 } 482 continue // ignore 483 } 484 485 // use named receiver type if available (for better error messages) 486 var recvTyp Type = ityp 487 if def != nil { 488 recvTyp = def 489 } 490 sig.recv = NewVar(name.Pos(), check.pkg, "", recvTyp) 491 492 m := NewFunc(name.Pos(), check.pkg, name.Name, sig) 493 check.recordDef(name, m) 494 ityp.methods = append(ityp.methods, m) 495 } else { 496 // We have an embedded interface and f.Type is its 497 // (possibly qualified) embedded type name. Collect 498 // it if it's a valid interface. 499 typ := check.typ(f.Type) 500 501 utyp := check.underlying(typ) 502 if _, ok := utyp.(*Interface); !ok { 503 if utyp != Typ[Invalid] { 504 check.errorf(f.Type, _InvalidIfaceEmbed, "%s is not an interface", typ) 505 } 506 continue 507 } 508 509 ityp.embeddeds = append(ityp.embeddeds, typ) 510 check.posMap[ityp] = append(check.posMap[ityp], f.Type.Pos()) 511 } 512 } 513 514 if len(ityp.methods) == 0 && len(ityp.embeddeds) == 0 { 515 // empty interface 516 ityp.allMethods = markComplete 517 return 518 } 519 520 // sort for API stability 521 sort.Sort(byUniqueMethodName(ityp.methods)) 522 sort.Stable(byUniqueTypeName(ityp.embeddeds)) 523 524 check.later(func() { check.completeInterface(ityp) }) 525} 526 527func (check *Checker) completeInterface(ityp *Interface) { 528 if ityp.allMethods != nil { 529 return 530 } 531 532 // completeInterface may be called via the LookupFieldOrMethod, 533 // MissingMethod, Identical, or IdenticalIgnoreTags external API 534 // in which case check will be nil. In this case, type-checking 535 // must be finished and all interfaces should have been completed. 536 if check == nil { 537 panic("internal error: incomplete interface") 538 } 539 540 if trace { 541 check.trace(token.NoPos, "complete %s", ityp) 542 check.indent++ 543 defer func() { 544 check.indent-- 545 check.trace(token.NoPos, "=> %s", ityp) 546 }() 547 } 548 549 // An infinitely expanding interface (due to a cycle) is detected 550 // elsewhere (Checker.validType), so here we simply assume we only 551 // have valid interfaces. Mark the interface as complete to avoid 552 // infinite recursion if the validType check occurs later for some 553 // reason. 554 ityp.allMethods = markComplete 555 556 // Methods of embedded interfaces are collected unchanged; i.e., the identity 557 // of a method I.m's Func Object of an interface I is the same as that of 558 // the method m in an interface that embeds interface I. On the other hand, 559 // if a method is embedded via multiple overlapping embedded interfaces, we 560 // don't provide a guarantee which "original m" got chosen for the embedding 561 // interface. See also issue #34421. 562 // 563 // If we don't care to provide this identity guarantee anymore, instead of 564 // reusing the original method in embeddings, we can clone the method's Func 565 // Object and give it the position of a corresponding embedded interface. Then 566 // we can get rid of the mpos map below and simply use the cloned method's 567 // position. 568 569 var seen objset 570 var methods []*Func 571 mpos := make(map[*Func]token.Pos) // method specification or method embedding position, for good error messages 572 addMethod := func(pos token.Pos, m *Func, explicit bool) { 573 switch other := seen.insert(m); { 574 case other == nil: 575 methods = append(methods, m) 576 mpos[m] = pos 577 case explicit: 578 check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name) 579 check.errorf(atPos(mpos[other.(*Func)]), _DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented 580 default: 581 // check method signatures after all types are computed (issue #33656) 582 check.atEnd(func() { 583 if !check.identical(m.typ, other.Type()) { 584 check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name) 585 check.errorf(atPos(mpos[other.(*Func)]), _DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented 586 } 587 }) 588 } 589 } 590 591 for _, m := range ityp.methods { 592 addMethod(m.pos, m, true) 593 } 594 595 posList := check.posMap[ityp] 596 for i, typ := range ityp.embeddeds { 597 pos := posList[i] // embedding position 598 typ, ok := check.underlying(typ).(*Interface) 599 if !ok { 600 // An error was reported when collecting the embedded types. 601 // Ignore it. 602 continue 603 } 604 check.completeInterface(typ) 605 for _, m := range typ.allMethods { 606 addMethod(pos, m, false) // use embedding position pos rather than m.pos 607 } 608 } 609 610 if methods != nil { 611 sort.Sort(byUniqueMethodName(methods)) 612 ityp.allMethods = methods 613 } 614} 615 616// byUniqueTypeName named type lists can be sorted by their unique type names. 617type byUniqueTypeName []Type 618 619func (a byUniqueTypeName) Len() int { return len(a) } 620func (a byUniqueTypeName) Less(i, j int) bool { return sortName(a[i]) < sortName(a[j]) } 621func (a byUniqueTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 622 623func sortName(t Type) string { 624 if named, _ := t.(*Named); named != nil { 625 return named.obj.Id() 626 } 627 return "" 628} 629 630// byUniqueMethodName method lists can be sorted by their unique method names. 631type byUniqueMethodName []*Func 632 633func (a byUniqueMethodName) Len() int { return len(a) } 634func (a byUniqueMethodName) Less(i, j int) bool { return a[i].Id() < a[j].Id() } 635func (a byUniqueMethodName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 636 637func (check *Checker) tag(t *ast.BasicLit) string { 638 if t != nil { 639 if t.Kind == token.STRING { 640 if val, err := strconv.Unquote(t.Value); err == nil { 641 return val 642 } 643 } 644 check.invalidAST(t, "incorrect tag syntax: %q", t.Value) 645 } 646 return "" 647} 648 649func (check *Checker) structType(styp *Struct, e *ast.StructType) { 650 list := e.Fields 651 if list == nil { 652 return 653 } 654 655 // struct fields and tags 656 var fields []*Var 657 var tags []string 658 659 // for double-declaration checks 660 var fset objset 661 662 // current field typ and tag 663 var typ Type 664 var tag string 665 add := func(ident *ast.Ident, embedded bool, pos token.Pos) { 666 if tag != "" && tags == nil { 667 tags = make([]string, len(fields)) 668 } 669 if tags != nil { 670 tags = append(tags, tag) 671 } 672 673 name := ident.Name 674 fld := NewField(pos, check.pkg, name, typ, embedded) 675 // spec: "Within a struct, non-blank field names must be unique." 676 if name == "_" || check.declareInSet(&fset, pos, fld) { 677 fields = append(fields, fld) 678 check.recordDef(ident, fld) 679 } 680 } 681 682 // addInvalid adds an embedded field of invalid type to the struct for 683 // fields with errors; this keeps the number of struct fields in sync 684 // with the source as long as the fields are _ or have different names 685 // (issue #25627). 686 addInvalid := func(ident *ast.Ident, pos token.Pos) { 687 typ = Typ[Invalid] 688 tag = "" 689 add(ident, true, pos) 690 } 691 692 for _, f := range list.List { 693 typ = check.typ(f.Type) 694 tag = check.tag(f.Tag) 695 if len(f.Names) > 0 { 696 // named fields 697 for _, name := range f.Names { 698 add(name, false, name.Pos()) 699 } 700 } else { 701 // embedded field 702 // spec: "An embedded type must be specified as a type name T or as a pointer 703 // to a non-interface type name *T, and T itself may not be a pointer type." 704 pos := f.Type.Pos() 705 name := embeddedFieldIdent(f.Type) 706 if name == nil { 707 check.invalidAST(f.Type, "embedded field type %s has no name", f.Type) 708 name = ast.NewIdent("_") 709 name.NamePos = pos 710 addInvalid(name, pos) 711 continue 712 } 713 t, isPtr := deref(typ) 714 // Because we have a name, typ must be of the form T or *T, where T is the name 715 // of a (named or alias) type, and t (= deref(typ)) must be the type of T. 716 switch t := t.Underlying().(type) { 717 case *Basic: 718 if t == Typ[Invalid] { 719 // error was reported before 720 addInvalid(name, pos) 721 continue 722 } 723 724 // unsafe.Pointer is treated like a regular pointer 725 if t.kind == UnsafePointer { 726 check.errorf(f.Type, _InvalidPtrEmbed, "embedded field type cannot be unsafe.Pointer") 727 addInvalid(name, pos) 728 continue 729 } 730 731 case *Pointer: 732 check.errorf(f.Type, _InvalidPtrEmbed, "embedded field type cannot be a pointer") 733 addInvalid(name, pos) 734 continue 735 736 case *Interface: 737 if isPtr { 738 check.errorf(f.Type, _InvalidPtrEmbed, "embedded field type cannot be a pointer to an interface") 739 addInvalid(name, pos) 740 continue 741 } 742 } 743 add(name, true, pos) 744 } 745 } 746 747 styp.fields = fields 748 styp.tags = tags 749} 750 751func embeddedFieldIdent(e ast.Expr) *ast.Ident { 752 switch e := e.(type) { 753 case *ast.Ident: 754 return e 755 case *ast.StarExpr: 756 // *T is valid, but **T is not 757 if _, ok := e.X.(*ast.StarExpr); !ok { 758 return embeddedFieldIdent(e.X) 759 } 760 case *ast.SelectorExpr: 761 return e.Sel 762 } 763 return nil // invalid embedded field 764} 765