return typecheck.Expr(typecheck.NodAddr(n)).(*ir.AddrExpr)
}
-// ITabLsym returns the LSym representing the itab for concreate type typ
-// implementing interface iface.
+// ITabLsym returns the LSym representing the itab for concrete type typ implementing
+// interface iface. A dummy tab will be created in the unusual case where typ doesn't
+// implement iface. Normally, this wouldn't happen, because the typechecker would
+// have reported a compile-time error. This situation can only happen when the
+// destination type of a type assert or a type in a type switch is parameterized, so
+// it may sometimes, but not always, be a type that can't implement the specified
+// interface.
func ITabLsym(typ, iface *types.Type) *obj.LSym {
s, existed := ir.Pkgs.Itab.LookupOK(typ.LinkString() + "," + iface.LinkString())
lsym := s.Linksym()
if !existed {
- writeITab(lsym, typ, iface)
+ writeITab(lsym, typ, iface, true)
}
return lsym
}
lsym := s.Linksym()
if !existed {
- writeITab(lsym, typ, iface)
+ writeITab(lsym, typ, iface, false)
}
n := ir.NewLinksymExpr(base.Pos, lsym, types.Types[types.TUINT8])
}
}
-// formalType replaces byte and rune aliases with real types.
+// formalType replaces predeclared aliases with real types.
// They've been separate internally to make error messages
// better, but we have to merge them in the reflect tables.
func formalType(t *types.Type) *types.Type {
- if t == types.ByteType || t == types.RuneType {
+ switch t {
+ case types.AnyType, types.ByteType, types.RuneType:
return types.Types[t.Kind()]
}
return t
}
}
-// writeITab writes the itab for concrete type typ implementing
-// interface iface.
-func writeITab(lsym *obj.LSym, typ, iface *types.Type) {
+// writeITab writes the itab for concrete type typ implementing interface iface. If
+// allowNonImplement is true, allow the case where typ does not implement iface, and just
+// create a dummy itab with zeroed-out method entries.
+func writeITab(lsym *obj.LSym, typ, iface *types.Type, allowNonImplement bool) {
// TODO(mdempsky): Fix methodWrapper, geneq, and genhash (and maybe
// others) to stop clobbering these.
oldpos, oldfn := base.Pos, ir.CurFunc
break
}
}
- if sigs[0].Sym.Name == "==" {
- sigs = sigs[1:]
- if len(sigs) == 0 {
- break
- }
- }
}
- if len(sigs) != 0 {
+ completeItab := len(sigs) == 0
+ if !allowNonImplement && !completeItab {
base.Fatalf("incomplete itab")
}
o = objw.Uint32(lsym, o, types.TypeHash(typ)) // copy of type hash
o += 4 // skip unused field
for _, fn := range entries {
- o = objw.SymPtrWeak(lsym, o, fn, 0) // method pointer for each method
+ if !completeItab {
+ // If typ doesn't implement iface, make method entries be zero.
+ o = objw.Uintptr(lsym, o, 0)
+ } else {
+ o = objw.SymPtrWeak(lsym, o, fn, 0) // method pointer for each method
+ }
}
// Nothing writes static itabs, so they are read only.
objw.Global(lsym, int32(o), int16(obj.DUPOK|obj.RODATA))
}
writeType(types.NewPtr(types.Types[types.TSTRING]))
writeType(types.NewPtr(types.Types[types.TUNSAFEPTR]))
+ if base.Flag.G > 0 {
+ writeType(types.AnyType)
+ }
// emit type structs for error and func(error) string.
// The latter is the type of an auto-generated wrapper.
// Target method uses shaped names.
targs2 := make([]*types.Type, len(targs))
+ origRParams := deref(orig).OrigSym().Def.(*ir.Name).Type().RParams()
for i, t := range targs {
- targs2[i] = typecheck.Shapify(t, i)
+ targs2[i] = typecheck.Shapify(t, i, origRParams[i])
}
targs = targs2
sym := typecheck.MakeFuncInstSym(ir.MethodSym(methodrcvr, method.Sym), targs, false, true)
if sym.Def == nil {
- // Currently we make sure that we have all the instantiations
- // we need by generating them all in ../noder/stencil.go:instantiateMethods
- // TODO: maybe there's a better, more incremental way to generate
- // only the instantiations we need?
- base.Fatalf("instantiation %s not found", sym.Name)
+ // Currently we make sure that we have all the
+ // instantiations we need by generating them all in
+ // ../noder/stencil.go:instantiateMethods
+ // Extra instantiations because of an inlined function
+ // should have been exported, and so available via
+ // Resolve.
+ in := typecheck.Resolve(ir.NewIdent(src.NoXPos, sym))
+ if in.Op() == ir.ONONAME {
+ base.Fatalf("instantiation %s not found", sym.Name)
+ }
+ sym = in.Sym()
}
target := ir.AsNode(sym.Def)
call = ir.NewCallExpr(base.Pos, ir.OCALL, target, args)
sym := typecheck.MakeDictSym(gf, targs, true)
// Dictionary should already have been generated by instantiateMethods().
+ // Extra dictionaries needed because of an inlined function should have been
+ // exported, and so available via Resolve.
if lsym := sym.Linksym(); len(lsym.P) == 0 {
- base.Fatalf("Dictionary should have already been generated: %s.%s", sym.Pkg.Path, sym.Name)
+ in := typecheck.Resolve(ir.NewIdent(src.NoXPos, sym))
+ if in.Op() == ir.ONONAME {
+ base.Fatalf("Dictionary should have already been generated: %s.%s", sym.Pkg.Path, sym.Name)
+ }
+ sym = in.Sym()
}
// Make (or reuse) a node referencing the dictionary symbol.