// Souffle - A Datalog Compiler
// Copyright (c) 2018, The Souffle Developers. All rights reserved
// Licensed under the Universal Permissive License v 1.0 as shown at:
// - https://opensource.org/licenses/UPL
// - <souffle root>/licenses/SOUFFLE-UPL.txt

// Tests the aggregator-witness semantic check
// Should throw an error if an argument is grounded in the inner scope of an aggregator,
// but appears ungrounded in the outer scope.

.decl b(x:number)
b(1).

.decl c(x:number, y:number)
c(2,3).

.decl d(x:number)
d(4).

.decl e(x:number)
e(5).

.decl a(x:number, y:number)
// Valid
a(x,y) :- b(x), y = max z : { c(x,z) }.

// Valid - groundedness should propagate down the levels
// a(x,y) :- b(x), y = max z : { c(r,z), !d(x), r = count :  { e(x) } }.

// Valid for the same reason as above
a(x, y) :- b(x), y = max z : { c(_, z), !d(x) }.

// Invalid because of the variable x and the aggregator type is count/sum
a(x,y) :- y = count : { c(x,_) }.
a(x,y) :- y = sum z : { c(x,z) }.

// Valid because witnesses can be exported from min/max aggregates
a(x,y) :- y = max z : { c(x,z) }.
a(x,y) :- y = min z : { c(x,z) }.

// Invalid because witnesses cannot be exported from a sum aggregate
a(x,y) :- b(x), x = sum z : { c(y, z) }.

// Invalid because witnesses cannot be exported from a count aggregate
a(x, y) :- b(x+1), y = count : { c(x, _) }.

// Valid because the ungrounded occurrence of r can transfer from
// the aggregate body
a(x, y) :- r < 10, d(x), y = min z : { e(r), c(r, z) }.

// Invalid only because the sum aggregate cannot contain a witness
a(x,y) :- b(x), y = max z : { !d(r), !e(m), c(x,z), m = sum j : { c(r,j) } }.

// Invalid because we cannot export a witness from a count
a(x,y) :- y = sum z : { c(z,m), m = count : { e(x) } }.

// Invalid because of the variable y and the nested variable m
a(x,y) :- b(x), x = sum z : { c(z,y), !c(y,m), z = sum j : { c(j,m) } }.

.output a()
