@@ -265,7 +265,6 @@ func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) {
265
265
if ! check .allowVersion (check .pkg , 1 , 18 ) {
266
266
check .softErrorf (inNode (e , ix .Lbrack ), _Todo , "type instantiation requires go1.18 or later" )
267
267
}
268
- // TODO(rfindley): type instantiation should require go1.18
269
268
return check .instantiatedType (ix .X , ix .Indices , def )
270
269
271
270
case * ast.ParenExpr :
@@ -375,13 +374,24 @@ func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) {
375
374
return typ
376
375
}
377
376
378
- func (check * Checker ) instantiatedType (x ast.Expr , targsx []ast.Expr , def * Named ) Type {
377
+ func (check * Checker ) instantiatedType (x ast.Expr , targsx []ast.Expr , def * Named ) (res Type ) {
378
+ if trace {
379
+ check .trace (x .Pos (), "-- instantiating %s with %s" , x , targsx )
380
+ check .indent ++
381
+ defer func () {
382
+ check .indent --
383
+ // Don't format the underlying here. It will always be nil.
384
+ check .trace (x .Pos (), "=> %s" , res )
385
+ }()
386
+ }
387
+
379
388
gtyp := check .genericType (x , true )
380
389
if gtyp == Typ [Invalid ] {
381
390
return gtyp // error already reported
382
391
}
383
- base , _ := gtyp .(* Named )
384
- if base == nil {
392
+
393
+ origin , _ := gtyp .(* Named )
394
+ if origin == nil {
385
395
panic (fmt .Sprintf ("%v: cannot instantiate %v" , x .Pos (), gtyp ))
386
396
}
387
397
@@ -398,17 +408,64 @@ func (check *Checker) instantiatedType(x ast.Expr, targsx []ast.Expr, def *Named
398
408
posList [i ] = arg .Pos ()
399
409
}
400
410
401
- typ := check .instantiate (x .Pos (), base , targs , posList )
402
- def .setUnderlying (typ )
403
- check .recordInstance (x , targs , typ )
411
+ // create the instance
412
+ h := check .conf .Context .typeHash (origin , targs )
413
+ // targs may be incomplete, and require inference. In any case we should de-duplicate.
414
+ inst := check .conf .Context .typeForHash (h , nil )
415
+ // If inst is non-nil, we can't just return here. Inst may have been
416
+ // constructed via recursive substitution, in which case we wouldn't do the
417
+ // validation below. Ensure that the validation (and resulting errors) runs
418
+ // for each instantiated type in the source.
419
+ if inst == nil {
420
+ tname := NewTypeName (x .Pos (), origin .obj .pkg , origin .obj .name , nil )
421
+ inst = check .newNamed (tname , origin , nil , nil , nil ) // underlying, methods and tparams are set when named is resolved
422
+ inst .targs = NewTypeList (targs )
423
+ inst = check .conf .Context .typeForHash (h , inst )
424
+ }
425
+ def .setUnderlying (inst )
426
+
427
+ inst .resolver = func (ctxt * Context , n * Named ) (* TypeParamList , Type , []* Func ) {
428
+ tparams := origin .TypeParams ().list ()
429
+
430
+ inferred := targs
431
+ if len (targs ) < len (tparams ) {
432
+ // If inference fails, len(inferred) will be 0, and inst.underlying will
433
+ // be set to Typ[Invalid] in expandNamed.
434
+ inferred = check .infer (x , tparams , targs , nil , nil )
435
+ if len (inferred ) > len (targs ) {
436
+ inst .targs = NewTypeList (inferred )
437
+ }
438
+ }
404
439
405
- // make sure we check instantiation works at least once
406
- // and that the resulting type is valid
440
+ check .recordInstance (x , inferred , inst )
441
+ return expandNamed (ctxt , n , x .Pos ())
442
+ }
443
+
444
+ // origin.tparams may not be set up, so we need to do expansion later.
407
445
check .later (func () {
408
- check .validType (typ , nil )
446
+ // This is an instance from the source, not from recursive substitution,
447
+ // and so it must be resolved during type-checking so that we can report
448
+ // errors.
449
+ inst .resolve (check .conf .Context )
450
+ // Since check is non-nil, we can still mutate inst. Unpinning the resolver
451
+ // frees some memory.
452
+ inst .resolver = nil
453
+
454
+ if check .validateTArgLen (x .Pos (), inst .tparams .Len (), inst .targs .Len ()) {
455
+ if i , err := check .verify (x .Pos (), inst .tparams .list (), inst .targs .list ()); err != nil {
456
+ // best position for error reporting
457
+ pos := x .Pos ()
458
+ if i < len (posList ) {
459
+ pos = posList [i ]
460
+ }
461
+ check .softErrorf (atPos (pos ), _Todo , err .Error ())
462
+ }
463
+ }
464
+
465
+ check .validType (inst , nil )
409
466
})
410
467
411
- return typ
468
+ return inst
412
469
}
413
470
414
471
// arrayLength type-checks the array length expression e
0 commit comments