Skip to content

Commit 2872496

Browse files
committed
cmd/compile/internal/types2: systematic detection of missing instantiation
When type-checking expressions, detection of uninstantiated generic functions and types was somewhat ad-hoc. Add an extra parameter "allowGenerics" to rawExpr. If not set, the result operand cannot be generic. The only place where rawExpr is called with allowGenerics != false is from exprOrType, which passes an allowGenerics parameter through. The only place where exprOrType is called with allowGenerics == true is when handling index expressions and calls. Make sure that we only accept generic operands where expected, and check the other branches. As a result, a recently added varType call (CL 345970) can be removed again. This also fixes a bug where an error for a conversion to generic type was reported after the conversion (i.e., with the converted value, rather than the generic type). Added a test case for that. For #48048. Change-Id: I8576326f5fcfb58d78b3ce8572068aa32e66c568 Reviewed-on: https://go-review.googlesource.com/c/go/+/346471 Trust: Robert Griesemer <[email protected]> Run-TryBot: Robert Griesemer <[email protected]> Reviewed-by: Robert Findley <[email protected]>
1 parent 0bfd6fc commit 2872496

File tree

7 files changed

+66
-21
lines changed

7 files changed

+66
-21
lines changed

src/cmd/compile/internal/types2/builtins.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -763,7 +763,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
763763
var t operand
764764
x1 := x
765765
for _, arg := range call.ArgList {
766-
check.rawExpr(x1, arg, nil) // permit trace for types, e.g.: new(trace(T))
766+
check.rawExpr(x1, arg, nil, false) // permit trace for types, e.g.: new(trace(T))
767767
check.dump("%v: %s", posFor(x1), x1)
768768
x1 = &t // use incoming x only for first argument
769769
}

src/cmd/compile/internal/types2/call.go

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,9 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind {
8383
x.expr = iexpr
8484
check.record(x)
8585
} else {
86-
check.exprOrType(x, call.Fun)
86+
check.exprOrType(x, call.Fun, true)
8787
}
88+
// x.typ may be generic
8889

8990
switch x.mode {
9091
case invalid:
@@ -94,6 +95,10 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind {
9495

9596
case typexpr:
9697
// conversion
98+
check.nonGeneric(x)
99+
if x.mode == invalid {
100+
return conversion
101+
}
97102
T := x.typ
98103
x.mode = invalid
99104
switch n := len(call.ArgList); n {
@@ -122,6 +127,7 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind {
122127
return conversion
123128

124129
case builtin:
130+
// no need to check for non-genericity here
125131
id := x.id
126132
if !check.builtin(x, call, id) {
127133
x.mode = invalid
@@ -135,6 +141,7 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind {
135141
}
136142

137143
// ordinary function/method call
144+
// signature may be generic
138145
cgocall := x.mode == cgofunc
139146

140147
sig := asSignature(x.typ)
@@ -474,15 +481,11 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) {
474481
}
475482
}
476483

477-
check.exprOrType(x, e.X)
484+
check.exprOrType(x, e.X, false)
478485
if x.mode == invalid {
479486
goto Error
480487
}
481488

482-
if x.mode == typexpr {
483-
x.typ = check.varType(e.X)
484-
}
485-
486489
obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
487490
if obj == nil {
488491
switch {
@@ -683,7 +686,7 @@ func (check *Checker) use(arg ...syntax.Expr) {
683686
check.use(l.ElemList...)
684687
continue
685688
}
686-
check.rawExpr(&x, e, nil)
689+
check.rawExpr(&x, e, nil, false)
687690
}
688691
}
689692

@@ -714,7 +717,7 @@ func (check *Checker) useLHS(arg ...syntax.Expr) {
714717
}
715718
}
716719
}
717-
check.rawExpr(&x, e, nil)
720+
check.rawExpr(&x, e, nil, false)
718721
if v != nil {
719722
v.used = v_used // restore v.used
720723
}

src/cmd/compile/internal/types2/expr.go

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,8 +1085,10 @@ const (
10851085
// rawExpr typechecks expression e and initializes x with the expression
10861086
// value or type. If an error occurred, x.mode is set to invalid.
10871087
// If hint != nil, it is the type of a composite literal element.
1088+
// If allowGeneric is set, the operand type may be an uninstantiated
1089+
// parameterized type or function value.
10881090
//
1089-
func (check *Checker) rawExpr(x *operand, e syntax.Expr, hint Type) exprKind {
1091+
func (check *Checker) rawExpr(x *operand, e syntax.Expr, hint Type, allowGeneric bool) exprKind {
10901092
if check.conf.Trace {
10911093
check.trace(e.Pos(), "expr %s", e)
10921094
check.indent++
@@ -1097,11 +1099,40 @@ func (check *Checker) rawExpr(x *operand, e syntax.Expr, hint Type) exprKind {
10971099
}
10981100

10991101
kind := check.exprInternal(x, e, hint)
1102+
1103+
if !allowGeneric {
1104+
check.nonGeneric(x)
1105+
}
1106+
11001107
check.record(x)
11011108

11021109
return kind
11031110
}
11041111

1112+
// If x is a generic function or type, nonGeneric reports an error and invalidates x.mode and x.typ.
1113+
// Otherwise it leaves x alone.
1114+
func (check *Checker) nonGeneric(x *operand) {
1115+
if x.mode == invalid || x.mode == novalue {
1116+
return
1117+
}
1118+
var what string
1119+
switch t := x.typ.(type) {
1120+
case *Named:
1121+
if isGeneric(t) {
1122+
what = "type"
1123+
}
1124+
case *Signature:
1125+
if t.tparams != nil {
1126+
what = "function"
1127+
}
1128+
}
1129+
if what != "" {
1130+
check.errorf(x.expr, "cannot use generic %s %s without instantiation", what, x.expr)
1131+
x.mode = invalid
1132+
x.typ = Typ[Invalid]
1133+
}
1134+
}
1135+
11051136
// exprInternal contains the core of type checking of expressions.
11061137
// Must only be called by rawExpr.
11071138
//
@@ -1386,7 +1417,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
13861417
x.typ = typ
13871418

13881419
case *syntax.ParenExpr:
1389-
kind := check.rawExpr(x, e.X, nil)
1420+
kind := check.rawExpr(x, e.X, nil, false)
13901421
x.expr = e
13911422
return kind
13921423

@@ -1468,7 +1499,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
14681499
// unary expression
14691500
if e.Op == syntax.Mul {
14701501
// pointer indirection
1471-
check.exprOrType(x, e.X)
1502+
check.exprOrType(x, e.X, false)
14721503
switch x.mode {
14731504
case invalid:
14741505
goto Error
@@ -1595,14 +1626,14 @@ func (check *Checker) typeAssertion(pos syntax.Pos, x *operand, xtyp *Interface,
15951626
// If an error occurred, x.mode is set to invalid.
15961627
//
15971628
func (check *Checker) expr(x *operand, e syntax.Expr) {
1598-
check.rawExpr(x, e, nil)
1629+
check.rawExpr(x, e, nil, false)
15991630
check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
16001631
check.singleValue(x)
16011632
}
16021633

16031634
// multiExpr is like expr but the result may also be a multi-value.
16041635
func (check *Checker) multiExpr(x *operand, e syntax.Expr) {
1605-
check.rawExpr(x, e, nil)
1636+
check.rawExpr(x, e, nil, false)
16061637
check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
16071638
}
16081639

@@ -1612,16 +1643,18 @@ func (check *Checker) multiExpr(x *operand, e syntax.Expr) {
16121643
//
16131644
func (check *Checker) exprWithHint(x *operand, e syntax.Expr, hint Type) {
16141645
assert(hint != nil)
1615-
check.rawExpr(x, e, hint)
1646+
check.rawExpr(x, e, hint, false)
16161647
check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
16171648
check.singleValue(x)
16181649
}
16191650

16201651
// exprOrType typechecks expression or type e and initializes x with the expression value or type.
1652+
// If allowGeneric is set, the operand type may be an uninstantiated parameterized type or function
1653+
// value.
16211654
// If an error occurred, x.mode is set to invalid.
16221655
//
1623-
func (check *Checker) exprOrType(x *operand, e syntax.Expr) {
1624-
check.rawExpr(x, e, nil)
1656+
func (check *Checker) exprOrType(x *operand, e syntax.Expr, allowGeneric bool) {
1657+
check.rawExpr(x, e, nil, allowGeneric)
16251658
check.exclude(x, 1<<novalue)
16261659
check.singleValue(x)
16271660
}

src/cmd/compile/internal/types2/index.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ import (
1515
// In that case x represents the uninstantiated function value and
1616
// it is the caller's responsibility to instantiate the function.
1717
func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst bool) {
18-
check.exprOrType(x, e.X)
18+
check.exprOrType(x, e.X, true)
19+
// x may be generic
1920

2021
switch x.mode {
2122
case invalid:
@@ -25,6 +26,7 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
2526
case typexpr:
2627
// type instantiation
2728
x.mode = invalid
29+
// TODO(gri) here we re-evaluate e.X - try to avoid this
2830
x.typ = check.varType(e)
2931
if x.typ != Typ[Invalid] {
3032
x.mode = typexpr
@@ -38,6 +40,12 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
3840
}
3941
}
4042

43+
// x should not be generic at this point, but be safe and check
44+
check.nonGeneric(x)
45+
if x.mode == invalid {
46+
return false
47+
}
48+
4149
// ordinary index expression
4250
valid := false
4351
length := int64(-1) // valid if >= 0

src/cmd/compile/internal/types2/stmt.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ func (check *Checker) closeScope() {
170170
func (check *Checker) suspendedCall(keyword string, call *syntax.CallExpr) {
171171
var x operand
172172
var msg string
173-
switch check.rawExpr(&x, call, nil) {
173+
switch check.rawExpr(&x, call, nil, false) {
174174
case conversion:
175175
msg = "requires function call, not conversion"
176176
case expression:
@@ -386,7 +386,7 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
386386
// function and method calls and receive operations can appear
387387
// in statement context. Such statements may be parenthesized."
388388
var x operand
389-
kind := check.rawExpr(&x, s.X, nil)
389+
kind := check.rawExpr(&x, s.X, nil, false)
390390
var msg string
391391
switch x.mode {
392392
default:

src/cmd/compile/internal/types2/testdata/examples/types.go2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ func _() {
102102

103103
// Generic types cannot be used without instantiation.
104104
var _ T // ERROR cannot use generic type T
105+
var _ = T /* ERROR cannot use generic type T */ (0)
105106

106107
// In type context, generic (parameterized) types cannot be parenthesized before
107108
// being instantiated. See also NOTES entry from 12/4/2019.

src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ var x T25 /* ERROR without instantiation */ .m1
8585

8686
// crash 26
8787
type T26 = interface{ F26[ /* ERROR cannot have type parameters */ Z any]() }
88-
func F26[Z any]() T26 { return F26 /* ERROR without instantiation */ /* ERROR missing method */ [] /* ERROR operand */ }
88+
func F26[Z any]() T26 { return F26 /* ERROR without instantiation */ [] /* ERROR operand */ }
8989

9090
// crash 27
9191
func e27[T any]() interface{ x27 /* ERROR not a type */ } { panic(0) }

0 commit comments

Comments
 (0)