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