(e ast.Expr)
| 546 | } |
| 547 | |
| 548 | func (c *checker) checkComprehension(e ast.Expr) { |
| 549 | comp := e.AsComprehension() |
| 550 | c.check(comp.IterRange()) |
| 551 | c.check(comp.AccuInit()) |
| 552 | rangeType := substitute(c.mappings, c.getType(comp.IterRange()), false) |
| 553 | |
| 554 | // Create a scope for the comprehension since it has a local accumulation variable. |
| 555 | // This scope will contain the accumulation variable used to compute the result. |
| 556 | accuType := c.getType(comp.AccuInit()) |
| 557 | c.env = c.env.enterScope() |
| 558 | c.env.AddIdents(decls.NewVariable(comp.AccuVar(), accuType)) |
| 559 | |
| 560 | var varType, var2Type *types.Type |
| 561 | switch rangeType.Kind() { |
| 562 | case types.ListKind: |
| 563 | // varType represents the list element type for one-variable comprehensions. |
| 564 | varType = rangeType.Parameters()[0] |
| 565 | if comp.HasIterVar2() { |
| 566 | // varType represents the list index (int) for two-variable comprehensions, |
| 567 | // and var2Type represents the list element type. |
| 568 | var2Type = varType |
| 569 | varType = types.IntType |
| 570 | } |
| 571 | case types.MapKind: |
| 572 | // varType represents the map entry key for all comprehension types. |
| 573 | varType = rangeType.Parameters()[0] |
| 574 | if comp.HasIterVar2() { |
| 575 | // var2Type represents the map entry value for two-variable comprehensions. |
| 576 | var2Type = rangeType.Parameters()[1] |
| 577 | } |
| 578 | case types.DynKind, types.ErrorKind, types.TypeParamKind: |
| 579 | // Set the range type to DYN to prevent assignment to a potentially incorrect type |
| 580 | // at a later point in type-checking. The isAssignable call will update the type |
| 581 | // substitutions for the type param under the covers. |
| 582 | c.isAssignable(types.DynType, rangeType) |
| 583 | // Set the range iteration variable to type DYN as well. |
| 584 | varType = types.DynType |
| 585 | if comp.HasIterVar2() { |
| 586 | var2Type = types.DynType |
| 587 | } |
| 588 | default: |
| 589 | c.errors.notAComprehensionRange(comp.IterRange().ID(), c.location(comp.IterRange()), rangeType) |
| 590 | varType = types.ErrorType |
| 591 | if comp.HasIterVar2() { |
| 592 | var2Type = types.ErrorType |
| 593 | } |
| 594 | } |
| 595 | |
| 596 | // Create a block scope for the loop. |
| 597 | c.env = c.env.enterScope() |
| 598 | c.env.AddIdents(decls.NewVariable(comp.IterVar(), varType)) |
| 599 | if comp.HasIterVar2() { |
| 600 | c.env.AddIdents(decls.NewVariable(comp.IterVar2(), var2Type)) |
| 601 | } |
| 602 | // Check the variable references in the condition and step. |
| 603 | c.check(comp.LoopCondition()) |
| 604 | c.assertType(comp.LoopCondition(), types.BoolType) |
| 605 | c.check(comp.LoopStep()) |
no test coverage detected