@@ -9,6 +9,7 @@ package types2
9
9
import (
10
10
"bytes"
11
11
"cmd/compile/internal/syntax"
12
+ "fmt"
12
13
)
13
14
14
15
const useConstraintTypeInference = true
@@ -409,6 +410,34 @@ func (check *Checker) inferB(tparams []*TypeParam, targs []Type, report bool) (t
409
410
}
410
411
}
411
412
413
+ // The data structure of each (provided or inferred) type represents a graph, where
414
+ // each node corresponds to a type and each (directed) vertice points to a component
415
+ // type. The substitution process described above repeatedly replaces type parameter
416
+ // nodes in these graphs with the graphs of the types the type parameters stand for,
417
+ // which creates a new (possibly bigger) graph for each type.
418
+ // The substitution process will not stop if the replacement graph for a type parameter
419
+ // also contains that type parameter.
420
+ // For instance, for [A interface{ *A }], without any type argument provided for A,
421
+ // unification produces the type list [*A]. Substituting A in *A with the value for
422
+ // A will lead to infinite expansion by producing [**A], [****A], [********A], etc.,
423
+ // because the graph A -> *A has a cycle through A.
424
+ // Generally, cycles may occur across multiple type parameters and inferred types
425
+ // (for instance, consider [P interface{ *Q }, Q interface{ func(P) }]).
426
+ // We eliminate cycles by walking the graphs for all type parameters. If a cycle
427
+ // through a type parameter is detected, cycleFinder nils out the respectice type
428
+ // which kills the cycle; this also means that the respective type could not be
429
+ // inferred.
430
+ //
431
+ // TODO(gri) If useful, we could report the respective cycle as an error. We don't
432
+ // do this now because type inference will fail anyway, and furthermore,
433
+ // constraints with cycles of this kind cannot currently be satisfied by
434
+ // any user-suplied type. But should that change, reporting an error
435
+ // would be wrong.
436
+ w := cycleFinder {tparams , types , make (map [Type ]bool )}
437
+ for _ , t := range tparams {
438
+ w .typ (t ) // t != nil
439
+ }
440
+
412
441
// dirty tracks the indices of all types that may still contain type parameters.
413
442
// We know that nil type entries and entries corresponding to provided (non-nil)
414
443
// type arguments are clean, so exclude them from the start.
@@ -457,3 +486,98 @@ func (check *Checker) inferB(tparams []*TypeParam, targs []Type, report bool) (t
457
486
458
487
return
459
488
}
489
+
490
+ type cycleFinder struct {
491
+ tparams []* TypeParam
492
+ types []Type
493
+ seen map [Type ]bool
494
+ }
495
+
496
+ func (w * cycleFinder ) typ (typ Type ) {
497
+ if w .seen [typ ] {
498
+ // We have seen typ before. If it is one of the type parameters
499
+ // in tparams, iterative substitution will lead to infinite expansion.
500
+ // Nil out the corresponding type which effectively kills the cycle.
501
+ if tpar , _ := typ .(* TypeParam ); tpar != nil {
502
+ if i := tparamIndex (w .tparams , tpar ); i >= 0 {
503
+ // cycle through tpar
504
+ w .types [i ] = nil
505
+ }
506
+ }
507
+ // If we don't have one of our type parameters, the cycle is due
508
+ // to an ordinary recursive type and we can just stop walking it.
509
+ return
510
+ }
511
+ w .seen [typ ] = true
512
+ defer delete (w .seen , typ )
513
+
514
+ switch t := typ .(type ) {
515
+ case * Basic , * top :
516
+ // nothing to do
517
+
518
+ case * Array :
519
+ w .typ (t .elem )
520
+
521
+ case * Slice :
522
+ w .typ (t .elem )
523
+
524
+ case * Struct :
525
+ w .varList (t .fields )
526
+
527
+ case * Pointer :
528
+ w .typ (t .base )
529
+
530
+ // case *Tuple:
531
+ // This case should not occur because tuples only appear
532
+ // in signatures where they are handled explicitly.
533
+
534
+ case * Signature :
535
+ // There are no "method types" so we should never see a recv.
536
+ assert (t .recv == nil )
537
+ if t .params != nil {
538
+ w .varList (t .params .vars )
539
+ }
540
+ if t .results != nil {
541
+ w .varList (t .results .vars )
542
+ }
543
+
544
+ case * Union :
545
+ for _ , t := range t .terms {
546
+ w .typ (t .typ )
547
+ }
548
+
549
+ case * Interface :
550
+ for _ , m := range t .methods {
551
+ w .typ (m .typ )
552
+ }
553
+ for _ , t := range t .embeddeds {
554
+ w .typ (t )
555
+ }
556
+
557
+ case * Map :
558
+ w .typ (t .key )
559
+ w .typ (t .elem )
560
+
561
+ case * Chan :
562
+ w .typ (t .elem )
563
+
564
+ case * Named :
565
+ for _ , tpar := range t .TArgs ().list () {
566
+ w .typ (tpar )
567
+ }
568
+
569
+ case * TypeParam :
570
+ if i := tparamIndex (w .tparams , t ); i >= 0 && w .types [i ] != nil {
571
+ w .typ (w .types [i ])
572
+ }
573
+
574
+ default :
575
+ panic (fmt .Sprintf ("unexpected %T" , typ ))
576
+ }
577
+ }
578
+
579
+ func (w * cycleFinder ) varList (list []* Var ) {
580
+ for _ , v := range list {
581
+ w .typ (v .typ )
582
+ }
583
+ }
0 commit comments