diff --git a/Makefile b/Makefile index 9868b17f91..2db2ac71da 100644 --- a/Makefile +++ b/Makefile @@ -302,6 +302,8 @@ test-corpus-wasi: wasi-libc .PHONY: smoketest smoketest: $(TINYGO) version + # compile-only platform-independent examples + cd tests/text/template/smoke && $(TINYGO) test -c && rm -f smoke.test # regression test for #2563 cd tests/os/smoke && $(TINYGO) test -c -target=pybadge && rm smoke.test # test all examples (except pwm) diff --git a/src/reflect/type.go b/src/reflect/type.go index 4ead369b29..f8aab85a61 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -126,6 +126,35 @@ func (k Kind) basicType() rawType { return rawType(k << 1) } +// Copied from reflect/type.go +// https://go.dev/src/reflect/type.go?#L348 + +// ChanDir represents a channel type's direction. +type ChanDir int + +const ( + RecvDir ChanDir = 1 << iota // <-chan + SendDir // chan<- + BothDir = RecvDir | SendDir // chan +) + +// Method represents a single method. +type Method struct { + // Name is the method name. + Name string + + // PkgPath is the package path that qualifies a lower case (unexported) + // method name. It is empty for upper case (exported) method names. + // The combination of PkgPath and Name uniquely identifies a method + // in a method set. + // See https://golang.org/ref/spec#Uniqueness_of_identifiers + PkgPath string + + Type Type // method type + Func Value // func with receiver as first argument + Index int // index for Type.Method +} + // The following Type type has been copied almost entirely from // https://github.com/golang/go/blob/go1.15/src/reflect/type.go#L27-L212. // Some methods have been commented out as they haven't yet been implemented. @@ -173,7 +202,7 @@ type Type interface { // // For an interface type, the returned Method's Type field gives the // method signature, without a receiver, and the Func field is nil. - //MethodByName(string) (Method, bool) + MethodByName(string) (Method, bool) // NumMethod returns the number of exported methods in the type's method set. NumMethod() int @@ -187,7 +216,7 @@ type Type interface { // If the type was predeclared (string, error) or not defined (*T, struct{}, // []int, or A where A is an alias for a non-defined type), the package path // will be the empty string. - //PkgPath() string + PkgPath() string // Size returns the number of bytes needed to store // a value of the given type; it is analogous to unsafe.Sizeof. @@ -234,7 +263,7 @@ type Type interface { // ChanDir returns a channel type's direction. // It panics if the type's Kind is not Chan. - //ChanDir() ChanDir + ChanDir() ChanDir // IsVariadic reports whether a function type's final input parameter // is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the parameter's @@ -248,7 +277,7 @@ type Type interface { // t.IsVariadic() == true // // IsVariadic panics if the type's Kind is not Func. - //IsVariadic() bool + IsVariadic() bool // Elem returns a type's element type. // It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice. @@ -267,7 +296,7 @@ type Type interface { // FieldByName returns the struct field with the given name // and a boolean indicating if the field was found. - //FieldByName(name string) (StructField, bool) + FieldByName(name string) (StructField, bool) // FieldByNameFunc returns the struct field with a name // that satisfies the match function and a boolean indicating if @@ -286,7 +315,7 @@ type Type interface { // In returns the type of a function type's i'th input parameter. // It panics if the type's Kind is not Func. // It panics if i is not in the range [0, NumIn()). - //In(i int) Type + In(i int) Type // Key returns a map type's key type. // It panics if the type's Kind is not Map. @@ -302,16 +331,16 @@ type Type interface { // NumIn returns a function type's input parameter count. // It panics if the type's Kind is not Func. - //NumIn() int + NumIn() int // NumOut returns a function type's output parameter count. // It panics if the type's Kind is not Func. - //NumOut() int + NumOut() int // Out returns the type of a function type's i'th output parameter. // It panics if the type's Kind is not Func. // It panics if i is not in the range [0, NumOut()). - //Out(i int) Type + Out(i int) Type } // The typecode as used in an interface{}. @@ -675,10 +704,26 @@ func (t rawType) Comparable() bool { } } +func (t rawType) ChanDir() ChanDir { + panic("unimplemented: (reflect.Type).ChanDir()") +} + func (t rawType) ConvertibleTo(u Type) bool { panic("unimplemented: (reflect.Type).ConvertibleTo()") } +func (t rawType) IsVariadic() bool { + panic("unimplemented: (reflect.Type).IsVariadic()") +} + +func (t rawType) NumIn() int { + panic("unimplemented: (reflect.Type).NumIn()") +} + +func (t rawType) NumOut() int { + panic("unimplemented: (reflect.Type).NumOut()") +} + func (t rawType) NumMethod() int { panic("unimplemented: (reflect.Type).NumMethod()") } @@ -691,6 +736,26 @@ func (t rawType) Key() Type { panic("unimplemented: (reflect.Type).Key()") } +func (t rawType) In(i int) Type { + panic("unimplemented: (reflect.Type).In()") +} + +func (t rawType) Out(i int) Type { + panic("unimplemented: (reflect.Type).Out()") +} + +func (t rawType) MethodByName(name string) (Method, bool) { + panic("unimplemented: (reflect.Type).MethodByName()") +} + +func (t rawType) PkgPath() string { + panic("unimplemented: (reflect.Type).PkgPath()") +} + +func (t rawType) FieldByName(name string) (StructField, bool) { + panic("unimplemented: (reflect.Type).FieldByName()") +} + // A StructField describes a single field in a struct. type StructField struct { // Name indicates the field name. @@ -704,6 +769,7 @@ type StructField struct { Tag StructTag // field tag string Anonymous bool Offset uintptr + Index []int // index sequence for Type.FieldByIndex } // IsExported reports whether the field is exported. @@ -800,3 +866,7 @@ func (e *TypeError) Error() string { func align(offset uintptr, alignment uintptr) uintptr { return (offset + alignment - 1) &^ (alignment - 1) } + +func SliceOf(t Type) Type { + panic("unimplemented: reflect.SliceOf()") +} diff --git a/src/reflect/value.go b/src/reflect/value.go index be086e5fea..d58ecba612 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -128,7 +128,7 @@ func (v Value) IsNil() bool { _, val := decomposeInterface(*(*interface{})(v.value)) return val == nil default: - panic(&ValueError{"IsNil"}) + panic(&ValueError{Method: "IsNil"}) } } @@ -144,7 +144,7 @@ func (v Value) Pointer() uintptr { case Func: panic("unimplemented: (reflect.Value).Pointer()") default: // not implemented: Func - panic(&ValueError{"Pointer"}) + panic(&ValueError{Method: "Pointer"}) } } @@ -187,7 +187,7 @@ func (v Value) Bool() bool { return uintptr(v.value) != 0 } default: - panic(&ValueError{"Bool"}) + panic(&ValueError{Method: "Bool"}) } } @@ -224,7 +224,7 @@ func (v Value) Int() int64 { return int64(int64(uintptr(v.value))) } default: - panic(&ValueError{"Int"}) + panic(&ValueError{Method: "Int"}) } } @@ -267,7 +267,7 @@ func (v Value) Uint() uint64 { return uint64(uintptr(v.value)) } default: - panic(&ValueError{"Uint"}) + panic(&ValueError{Method: "Uint"}) } } @@ -293,7 +293,7 @@ func (v Value) Float() float64 { return *(*float64)(unsafe.Pointer(&v.value)) } default: - panic(&ValueError{"Float"}) + panic(&ValueError{Method: "Float"}) } } @@ -315,7 +315,7 @@ func (v Value) Complex() complex128 { // architectures with 128-bit pointers, however. return *(*complex128)(v.value) default: - panic(&ValueError{"Complex"}) + panic(&ValueError{Method: "Complex"}) } } @@ -339,6 +339,10 @@ func (v Value) Slice(i, j int) Value { panic("unimplemented: (reflect.Value).Slice()") } +func (v Value) Slice3(i, j, k int) Value { + panic("unimplemented: (reflect.Value).Slice3()") +} + //go:linkname maplen runtime.hashmapLenUnsafePointer func maplen(p unsafe.Pointer) int @@ -360,7 +364,7 @@ func (v Value) Len() int { case String: return int((*stringHeader)(v.value).len) default: - panic(&ValueError{"Len"}) + panic(&ValueError{Method: "Len"}) } } @@ -378,7 +382,7 @@ func (v Value) Cap() int { case Slice: return int((*sliceHeader)(v.value).cap) default: - panic(&ValueError{"Cap"}) + panic(&ValueError{Method: "Cap"}) } } @@ -408,7 +412,7 @@ func (v Value) Elem() Value { flags: v.flags &^ valueFlagIndirect, } default: - panic(&ValueError{"Elem"}) + panic(&ValueError{Method: "Elem"}) } } @@ -552,7 +556,7 @@ func (v Value) Index(i int) Value { value: unsafe.Pointer(value), } default: - panic(&ValueError{"Index"}) + panic(&ValueError{Method: "Index"}) } } @@ -631,7 +635,7 @@ func (v Value) SetBool(x bool) { case Bool: *(*bool)(v.value) = x default: - panic(&ValueError{"SetBool"}) + panic(&ValueError{Method: "SetBool"}) } } @@ -649,7 +653,7 @@ func (v Value) SetInt(x int64) { case Int64: *(*int64)(v.value) = x default: - panic(&ValueError{"SetInt"}) + panic(&ValueError{Method: "SetInt"}) } } @@ -669,7 +673,7 @@ func (v Value) SetUint(x uint64) { case Uintptr: *(*uintptr)(v.value) = uintptr(x) default: - panic(&ValueError{"SetUint"}) + panic(&ValueError{Method: "SetUint"}) } } @@ -681,7 +685,7 @@ func (v Value) SetFloat(x float64) { case Float64: *(*float64)(v.value) = x default: - panic(&ValueError{"SetFloat"}) + panic(&ValueError{Method: "SetFloat"}) } } @@ -693,7 +697,7 @@ func (v Value) SetComplex(x complex128) { case Complex128: *(*complex128)(v.value) = x default: - panic(&ValueError{"SetComplex"}) + panic(&ValueError{Method: "SetComplex"}) } } @@ -703,7 +707,7 @@ func (v Value) SetString(x string) { case String: *(*string)(v.value) = x default: - panic(&ValueError{"SetString"}) + panic(&ValueError{Method: "SetString"}) } } @@ -788,10 +792,14 @@ type stringHeader struct { type ValueError struct { Method string + Kind Kind } func (e *ValueError) Error() string { - return "reflect: call of reflect.Value." + e.Method + " on invalid type" + if e.Kind == 0 { + return "reflect: call of " + e.Method + " on zero Value" + } + return "reflect: call of " + e.Method + " on " + e.Kind.String() + " Value" } // Calls to this function are converted to LLVM intrinsic calls such as @@ -865,3 +873,15 @@ func MakeMap(typ Type) Value { func (v Value) Call(in []Value) []Value { panic("unimplemented: (reflect.Value).Call()") } + +func (v Value) MethodByName(name string) Value { + panic("unimplemented: (reflect.Value).MethodByName()") +} + +func (v Value) Recv() (x Value, ok bool) { + panic("unimplemented: (reflect.Value).Recv()") +} + +func NewAt(typ Type, p unsafe.Pointer) Value { + panic("unimplemented: reflect.New()") +} diff --git a/tests/text/template/smoke/empty.go b/tests/text/template/smoke/empty.go new file mode 100644 index 0000000000..cbde21c394 --- /dev/null +++ b/tests/text/template/smoke/empty.go @@ -0,0 +1,4 @@ +package template_smoke + +func Function() { +} diff --git a/tests/text/template/smoke/smoke_test.go b/tests/text/template/smoke/smoke_test.go new file mode 100644 index 0000000000..c097f9e9af --- /dev/null +++ b/tests/text/template/smoke/smoke_test.go @@ -0,0 +1,112 @@ +//go:build go1.16 +// +build go1.16 + +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +package template_smoke_test + +import ( + "os" + "strings" + "testing" + "text/template" +) + +func TestExampleTemplate(tt *testing.T) { + // Define a template. + const letter = ` +Dear {{.Name}}, +{{if .Attended}} +It was a pleasure to see you at the wedding. +{{- else}} +It is a shame you couldn't make it to the wedding. +{{- end}} +{{with .Gift -}} +Thank you for the lovely {{.}}. +{{end}} +Best wishes, +Josie +` + + // Prepare some data to insert into the template. + type Recipient struct { + Name, Gift string + Attended bool + } + var recipients = []Recipient{ + {"Aunt Mildred", "bone china tea set", true}, + {"Uncle John", "moleskin pants", false}, + {"Cousin Rodney", "", false}, + } + + // Create a new template and parse the letter into it. + t := template.Must(template.New("letter").Parse(letter)) + + // Execute the template for each recipient. + for _, r := range recipients { + err := t.Execute(os.Stdout, r) + if err != nil { + tt.Log("executing template:", err) + } + } + + // Output: + // Dear Aunt Mildred, + // + // It was a pleasure to see you at the wedding. + // Thank you for the lovely bone china tea set. + // + // Best wishes, + // Josie + // + // Dear Uncle John, + // + // It is a shame you couldn't make it to the wedding. + // Thank you for the lovely moleskin pants. + // + // Best wishes, + // Josie + // + // Dear Cousin Rodney, + // + // It is a shame you couldn't make it to the wedding. + // + // Best wishes, + // Josie +} + +// The following example is duplicated in html/template; keep them in sync. + +func TestExampleTemplate_block(tt *testing.T) { + const ( + master = `Names:{{block "list" .}}{{"\n"}}{{range .}}{{println "-" .}}{{end}}{{end}}` + overlay = `{{define "list"}} {{join . ", "}}{{end}} ` + ) + var ( + funcs = template.FuncMap{"join": strings.Join} + guardians = []string{"Gamora", "Groot", "Nebula", "Rocket", "Star-Lord"} + ) + masterTmpl, err := template.New("master").Funcs(funcs).Parse(master) + if err != nil { + tt.Fatal(err) + } + overlayTmpl, err := template.Must(masterTmpl.Clone()).Parse(overlay) + if err != nil { + tt.Fatal(err) + } + if err := masterTmpl.Execute(os.Stdout, guardians); err != nil { + tt.Fatal(err) + } + if err := overlayTmpl.Execute(os.Stdout, guardians); err != nil { + tt.Fatal(err) + } + // Output: + // Names: + // - Gamora + // - Groot + // - Nebula + // - Rocket + // - Star-Lord + // Names: Gamora, Groot, Nebula, Rocket, Star-Lord +}