Skip to content

Commit

Permalink
Fix the occurs check to avoid adding types as substitutions for thems…
Browse files Browse the repository at this point in the history
…elves (#540)
  • Loading branch information
TristonianJones authored May 13, 2022
1 parent 362f01c commit 11b2ffc
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 2 deletions.
52 changes: 52 additions & 0 deletions checker/checker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1856,6 +1856,58 @@ _&&_(_==_(list~type(list(dyn))^list,
)~bool^logical_and
)~bool^logical_and`,
},
{
in: `[1].map(x, [x, x]).map(x, [x, x])`,
outType: decls.NewListType(decls.NewListType(decls.NewListType(decls.Int))),
out: `__comprehension__(
// Variable
x,
// Target
__comprehension__(
// Variable
x,
// Target
[
1~int
]~list(int),
// Accumulator
__result__,
// Init
[]~list(list(int)),
// LoopCondition
true~bool,
// LoopStep
_+_(
__result__~list(list(int))^__result__,
[
[
x~int^x,
x~int^x
]~list(int)
]~list(list(int))
)~list(list(int))^add_list,
// Result
__result__~list(list(int))^__result__)~list(list(int)),
// Accumulator
__result__,
// Init
[]~list(list(list(int))),
// LoopCondition
true~bool,
// LoopStep
_+_(
__result__~list(list(list(int)))^__result__,
[
[
x~list(int)^x,
x~list(int)^x
]~list(list(int))
]~list(list(list(int)))
)~list(list(list(int)))^add_list,
// Result
__result__~list(list(list(int)))^__result__)~list(list(list(int)))
`,
},
}

var testEnvs = map[string]testEnv{
Expand Down
10 changes: 8 additions & 2 deletions checker/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,15 @@ func internalIsAssignable(m *mapping, t1 *exprpb.Type, t2 *exprpb.Type) bool {
// - t2 has a type substitution (t2sub) assignable to t1
// - t2 does not occur within t1.
func isValidTypeSubstitution(m *mapping, t1, t2 *exprpb.Type) (valid, hasSub bool) {
// Early return if the t1 and t2 are the same instance.
kind1, kind2 := kindOf(t1), kindOf(t2)
if kind1 == kind2 && (t1 == t2 || proto.Equal(t1, t2)) {
return true, true
}
if t2Sub, found := m.find(t2); found {
kind1, kind2 := kindOf(t1), kindOf(t2)
if kind1 == kind2 && proto.Equal(t1, t2Sub) {
// Early return if t1 and t2Sub are the same instance as otherwise the mapping
// might mark a type as being a subtitution for itself.
if kind1 == kindOf(t2Sub) && (t1 == t2Sub || proto.Equal(t1, t2Sub)) {
return true, true
}
// If the types are compatible, pick the more general type and return true
Expand Down

0 comments on commit 11b2ffc

Please sign in to comment.