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:
Alan Donovan 2025-09-18 14:04:43 -04:00 committed by Gopher Robot
parent eb78f13c9f
commit 7bc1935db5
6 changed files with 56 additions and 6 deletions

View file

@ -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

View file

@ -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

View file

@ -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?

View file

@ -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
View 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")
}
}
}

View file

@ -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"
} }