mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile/internal: support new(expr)
This CL adds compiler support for new(expr), a feature of go1.26 that allows the user to specify the initial value of the variable instead of its type. Also, a basic test of dynamic behavior. See CL 704737 for spec change and CL 704935 for type-checker changes. For #45624 Change-Id: I65d27de1ee3aabb819b57cce8ea77f3073447757 Reviewed-on: https://go-review.googlesource.com/c/go/+/705157 Reviewed-by: Keith Randall <khr@golang.org> Reviewed-by: Mateusz Poliwczak <mpoliwczak34@gmail.com> Auto-Submit: Alan Donovan <adonovan@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Keith Randall <khr@google.com>
This commit is contained in:
parent
eb78f13c9f
commit
7bc1935db5
6 changed files with 56 additions and 6 deletions
|
|
@ -215,7 +215,7 @@ const (
|
||||||
ORSH // X >> Y
|
ORSH // X >> Y
|
||||||
OAND // X & Y
|
OAND // X & Y
|
||||||
OANDNOT // X &^ Y
|
OANDNOT // X &^ Y
|
||||||
ONEW // new(X); corresponds to calls to new in source code
|
ONEW // new(X); corresponds to calls to new(T) in source code
|
||||||
ONOT // !X
|
ONOT // !X
|
||||||
OBITNOT // ^X
|
OBITNOT // ^X
|
||||||
OPLUS // +X
|
OPLUS // +X
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,10 @@ func TypeNode(t *types.Type) Node {
|
||||||
|
|
||||||
// A DynamicType represents a type expression whose exact type must be
|
// A DynamicType represents a type expression whose exact type must be
|
||||||
// computed dynamically.
|
// computed dynamically.
|
||||||
|
//
|
||||||
|
// TODO(adonovan): I think "dynamic" is a misnomer here; it's really a
|
||||||
|
// type with free type parameters that needs to be instantiated to obtain
|
||||||
|
// a ground type for which an rtype can exist.
|
||||||
type DynamicType struct {
|
type DynamicType struct {
|
||||||
miniExpr
|
miniExpr
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2431,8 +2431,16 @@ func (r *reader) expr() (res ir.Node) {
|
||||||
|
|
||||||
case exprNew:
|
case exprNew:
|
||||||
pos := r.pos()
|
pos := r.pos()
|
||||||
typ := r.exprType()
|
if r.Bool() {
|
||||||
return typecheck.Expr(ir.NewUnaryExpr(pos, ir.ONEW, typ))
|
// new(expr) -> tmp := expr; &tmp
|
||||||
|
x := r.expr()
|
||||||
|
var init ir.Nodes
|
||||||
|
addr := ir.NewAddrExpr(pos, r.tempCopy(pos, x, &init))
|
||||||
|
addr.SetInit(init)
|
||||||
|
return typecheck.Expr(addr)
|
||||||
|
}
|
||||||
|
// new(T)
|
||||||
|
return typecheck.Expr(ir.NewUnaryExpr(pos, ir.ONEW, r.exprType()))
|
||||||
|
|
||||||
case exprSizeof:
|
case exprSizeof:
|
||||||
return ir.NewUintptr(r.pos(), r.typ().Size())
|
return ir.NewUintptr(r.pos(), r.typ().Size())
|
||||||
|
|
@ -3239,6 +3247,7 @@ func (r *reader) exprType() ir.Node {
|
||||||
var rtype, itab ir.Node
|
var rtype, itab ir.Node
|
||||||
|
|
||||||
if r.Bool() {
|
if r.Bool() {
|
||||||
|
// non-empty interface
|
||||||
typ, rtype, _, _, itab = r.itab(pos)
|
typ, rtype, _, _, itab = r.itab(pos)
|
||||||
if !typ.IsInterface() {
|
if !typ.IsInterface() {
|
||||||
rtype = nil // TODO(mdempsky): Leave set?
|
rtype = nil // TODO(mdempsky): Leave set?
|
||||||
|
|
|
||||||
|
|
@ -2035,10 +2035,16 @@ func (w *writer) expr(expr syntax.Expr) {
|
||||||
case "new":
|
case "new":
|
||||||
assert(len(expr.ArgList) == 1)
|
assert(len(expr.ArgList) == 1)
|
||||||
assert(!expr.HasDots)
|
assert(!expr.HasDots)
|
||||||
|
arg := expr.ArgList[0]
|
||||||
|
|
||||||
w.Code(exprNew)
|
w.Code(exprNew)
|
||||||
w.pos(expr)
|
w.pos(expr)
|
||||||
w.exprType(nil, expr.ArgList[0])
|
tv := w.p.typeAndValue(arg)
|
||||||
|
if w.Bool(!tv.IsType()) {
|
||||||
|
w.expr(arg) // new(expr), go1.26
|
||||||
|
} else {
|
||||||
|
w.exprType(nil, arg) // new(T)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
|
|
||||||
case "Sizeof":
|
case "Sizeof":
|
||||||
|
|
|
||||||
32
test/newexpr.go
Normal file
32
test/newexpr.go
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
// run
|
||||||
|
|
||||||
|
// Copyright 2025 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 main
|
||||||
|
|
||||||
|
// Issue #45624 is the proposal to accept new(expr) in go1.26.
|
||||||
|
// Here we test its run-time behavior.
|
||||||
|
func main() {
|
||||||
|
{
|
||||||
|
p := new(123) // untyped constant expr
|
||||||
|
if *p != 123 {
|
||||||
|
panic("wrong value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
x := 42
|
||||||
|
p := new(x) // non-constant expr
|
||||||
|
if *p != x {
|
||||||
|
panic("wrong value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
x := [2]int{123, 456}
|
||||||
|
p := new(x) // composite value
|
||||||
|
if *p != x {
|
||||||
|
panic("wrong value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -140,6 +140,5 @@ func _() {
|
||||||
_ = int // ERROR "type int is not an expression|not an expression"
|
_ = int // ERROR "type int is not an expression|not an expression"
|
||||||
(x) // ERROR "x .* not used|not used"
|
(x) // ERROR "x .* not used|not used"
|
||||||
_ = new(len) // ERROR "len.*must be called"
|
_ = new(len) // ERROR "len.*must be called"
|
||||||
// Disabled due to issue #43125.
|
_ = new(1 + 1) // ok
|
||||||
// _ = new(1 + 1) // DISABLED "1 \+ 1 is not a type"
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue