Skip to content

Commit 7bc1935

Browse files
adonovangopherbot
authored andcommitted
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 golang#45624 Change-Id: I65d27de1ee3aabb819b57cce8ea77f3073447757 Reviewed-on: https://go-review.googlesource.com/c/go/+/705157 Reviewed-by: Keith Randall <[email protected]> Reviewed-by: Mateusz Poliwczak <[email protected]> Auto-Submit: Alan Donovan <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Keith Randall <[email protected]>
1 parent eb78f13 commit 7bc1935

File tree

6 files changed

+56
-6
lines changed

6 files changed

+56
-6
lines changed

src/cmd/compile/internal/ir/node.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ const (
215215
ORSH // X >> Y
216216
OAND // X & Y
217217
OANDNOT // X &^ Y
218-
ONEW // new(X); corresponds to calls to new in source code
218+
ONEW // new(X); corresponds to calls to new(T) in source code
219219
ONOT // !X
220220
OBITNOT // ^X
221221
OPLUS // +X

src/cmd/compile/internal/ir/type.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ func TypeNode(t *types.Type) Node {
4242

4343
// A DynamicType represents a type expression whose exact type must be
4444
// computed dynamically.
45+
//
46+
// TODO(adonovan): I think "dynamic" is a misnomer here; it's really a
47+
// type with free type parameters that needs to be instantiated to obtain
48+
// a ground type for which an rtype can exist.
4549
type DynamicType struct {
4650
miniExpr
4751

src/cmd/compile/internal/noder/reader.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2431,8 +2431,16 @@ func (r *reader) expr() (res ir.Node) {
24312431

24322432
case exprNew:
24332433
pos := r.pos()
2434-
typ := r.exprType()
2435-
return typecheck.Expr(ir.NewUnaryExpr(pos, ir.ONEW, typ))
2434+
if r.Bool() {
2435+
// new(expr) -> tmp := expr; &tmp
2436+
x := r.expr()
2437+
var init ir.Nodes
2438+
addr := ir.NewAddrExpr(pos, r.tempCopy(pos, x, &init))
2439+
addr.SetInit(init)
2440+
return typecheck.Expr(addr)
2441+
}
2442+
// new(T)
2443+
return typecheck.Expr(ir.NewUnaryExpr(pos, ir.ONEW, r.exprType()))
24362444

24372445
case exprSizeof:
24382446
return ir.NewUintptr(r.pos(), r.typ().Size())
@@ -3239,6 +3247,7 @@ func (r *reader) exprType() ir.Node {
32393247
var rtype, itab ir.Node
32403248

32413249
if r.Bool() {
3250+
// non-empty interface
32423251
typ, rtype, _, _, itab = r.itab(pos)
32433252
if !typ.IsInterface() {
32443253
rtype = nil // TODO(mdempsky): Leave set?

src/cmd/compile/internal/noder/writer.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2035,10 +2035,16 @@ func (w *writer) expr(expr syntax.Expr) {
20352035
case "new":
20362036
assert(len(expr.ArgList) == 1)
20372037
assert(!expr.HasDots)
2038+
arg := expr.ArgList[0]
20382039

20392040
w.Code(exprNew)
20402041
w.pos(expr)
2041-
w.exprType(nil, expr.ArgList[0])
2042+
tv := w.p.typeAndValue(arg)
2043+
if w.Bool(!tv.IsType()) {
2044+
w.expr(arg) // new(expr), go1.26
2045+
} else {
2046+
w.exprType(nil, arg) // new(T)
2047+
}
20422048
return
20432049

20442050
case "Sizeof":

test/newexpr.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// run
2+
3+
// Copyright 2025 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package main
8+
9+
// Issue #45624 is the proposal to accept new(expr) in go1.26.
10+
// Here we test its run-time behavior.
11+
func main() {
12+
{
13+
p := new(123) // untyped constant expr
14+
if *p != 123 {
15+
panic("wrong value")
16+
}
17+
}
18+
{
19+
x := 42
20+
p := new(x) // non-constant expr
21+
if *p != x {
22+
panic("wrong value")
23+
}
24+
}
25+
{
26+
x := [2]int{123, 456}
27+
p := new(x) // composite value
28+
if *p != x {
29+
panic("wrong value")
30+
}
31+
}
32+
}

test/used.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,5 @@ func _() {
140140
_ = int // ERROR "type int is not an expression|not an expression"
141141
(x) // ERROR "x .* not used|not used"
142142
_ = new(len) // ERROR "len.*must be called"
143-
// Disabled due to issue #43125.
144-
// _ = new(1 + 1) // DISABLED "1 \+ 1 is not a type"
143+
_ = new(1 + 1) // ok
145144
}

0 commit comments

Comments
 (0)