-- in.cue --
self: t1: {
	a?: int
}

self: t2: {
	a!: int
	a!: int
}

unify: t1: p1: {
	a!: int
	a: int
}

unify: t1: p2: {
	a: int
	a!: int
}

unify: t2: p1: {
	a!: int
	a?: int
}

unify: t2: p2: {
	a?: int
	a!: int
}
#Def: t1: {
	a!: int
}

allowed: issue2306: {
	#A: a!: int
	#A: #B

	#B: b!: int
}

reference: {
	toWithinDefinition: p1:{
		#Foo: a!: int
		b: #Foo.a
	}
	toWithinDefinition: p2:{
		b: #Foo.a
		#Foo: a!: int
	}
	toFieldFromDefinition: p1: {
		#Foo: a!: int
		b: #Foo
		c: b.a
	}
	toFieldFromDefinition: p2: {
		c: b.a
		b: #Foo
		#Foo: a!: int
	}
	toNonDefinition: p1: {
		x: y!: _
		b: x.y
	}
	toNonDefinition: p2: {
		b: x.y
		x: y!: _
	}
	toConcrete: p1: {
		a!: 1
		b: a + 1
	}
	toConcrete: p2: {
		b: a + 1
		a!: 1
	}
}

-- out/compile --
--- in.cue
{
  self: {
    t1: {
      a?: int
    }
  }
  self: {
    t2: {
      a!: int
      a!: int
    }
  }
  unify: {
    t1: {
      p1: {
        a!: int
        a: int
      }
    }
  }
  unify: {
    t1: {
      p2: {
        a: int
        a!: int
      }
    }
  }
  unify: {
    t2: {
      p1: {
        a!: int
        a?: int
      }
    }
  }
  unify: {
    t2: {
      p2: {
        a?: int
        a!: int
      }
    }
  }
  #Def: {
    t1: {
      a!: int
    }
  }
  allowed: {
    issue2306: {
      #A: {
        a!: int
      }
      #A: 〈0;#B〉
      #B: {
        b!: int
      }
    }
  }
  reference: {
    toWithinDefinition: {
      p1: {
        #Foo: {
          a!: int
        }
        b: 〈0;#Foo〉.a
      }
    }
    toWithinDefinition: {
      p2: {
        b: 〈0;#Foo〉.a
        #Foo: {
          a!: int
        }
      }
    }
    toFieldFromDefinition: {
      p1: {
        #Foo: {
          a!: int
        }
        b: 〈0;#Foo〉
        c: 〈0;b〉.a
      }
    }
    toFieldFromDefinition: {
      p2: {
        c: 〈0;b〉.a
        b: 〈0;#Foo〉
        #Foo: {
          a!: int
        }
      }
    }
    toNonDefinition: {
      p1: {
        x: {
          y!: _
        }
        b: 〈0;x〉.y
      }
    }
    toNonDefinition: {
      p2: {
        b: 〈0;x〉.y
        x: {
          y!: _
        }
      }
    }
    toConcrete: {
      p1: {
        a!: 1
        b: (〈0;a〉 + 1)
      }
    }
    toConcrete: {
      p2: {
        b: (〈0;a〉 + 1)
        a!: 1
      }
    }
  }
}
-- out/eval/stats --
Leaks:  0
Freed:  66
Reused: 58
Allocs: 8
Retain: 10

Unifications: 66
Conjuncts:    90
Disjuncts:    76
-- out/evalalpha --
(_|_){
  // [eval]
  self: (struct){
    t1: (struct){
      a?: (int){ int }
    }
    t2: (struct){
      a!: (int){ int }
    }
  }
  unify: (struct){
    t1: (struct){
      p1: (struct){
        a: (int){ int }
      }
      p2: (struct){
        a: (int){ int }
      }
    }
    t2: (struct){
      p1: (struct){
        a!: (int){ int }
      }
      p2: (struct){
        a!: (int){ int }
      }
    }
  }
  #Def: (#struct){
    t1: (#struct){
      a!: (int){ int }
    }
  }
  allowed: (_|_){
    // [eval]
    issue2306: (_|_){
      // [eval]
      #A: (_|_){
        // [eval]
        a!: (_|_){
          // [eval] allowed.issue2306.#A.a: field not allowed:
          //     ./in.cue:34:6
        }
        b!: (int){ int }
      }
      #B: (#struct){
        b!: (int){ int }
      }
    }
  }
  reference: (struct){
    toWithinDefinition: (struct){
      p1: (struct){
        #Foo: (#struct){
          a!: (int){ int }
        }
        b: (int){ int }
      }
      p2: (struct){
        b: (int){ int }
        #Foo: (#struct){
          a!: (int){ int }
        }
      }
    }
    toFieldFromDefinition: (struct){
      p1: (struct){
        #Foo: (#struct){
          a!: (int){ int }
        }
        b: ~(reference.toFieldFromDefinition.p1.#Foo)
        c: (int){ int }
      }
      p2: (struct){
        c: (int){ int }
        b: ~(reference.toFieldFromDefinition.p2.#Foo)
        #Foo: (#struct){
          a!: (int){ int }
        }
      }
    }
    toNonDefinition: (struct){
      p1: (struct){
        x: (struct){
          y!: (_){ _ }
        }
        b: (_){ _ }
      }
      p2: (struct){
        b: (_){ _ }
        x: (struct){
          y!: (_){ _ }
        }
      }
    }
    toConcrete: (struct){
      p1: (struct){
        a!: (int){ 1 }
        b: (int){ 2 }
      }
      p2: (struct){
        b: (int){ 2 }
        a!: (int){ 1 }
      }
    }
  }
}
-- diff/-out/evalalpha<==>+out/eval --
diff old new
--- old
+++ new
@@ -40,8 +40,6 @@
         a!: (_|_){
           // [eval] allowed.issue2306.#A.a: field not allowed:
           //     ./in.cue:34:6
-          //     ./in.cue:35:6
-          //     ./in.cue:37:6
         }
         b!: (int){ int }
       }
@@ -70,16 +68,12 @@
         #Foo: (#struct){
           a!: (int){ int }
         }
-        b: (#struct){
-          a!: (int){ int }
-        }
-        c: (int){ int }
-      }
-      p2: (struct){
-        c: (int){ int }
-        b: (#struct){
-          a!: (int){ int }
-        }
+        b: ~(reference.toFieldFromDefinition.p1.#Foo)
+        c: (int){ int }
+      }
+      p2: (struct){
+        c: (int){ int }
+        b: ~(reference.toFieldFromDefinition.p2.#Foo)
         #Foo: (#struct){
           a!: (int){ int }
         }
-- diff/todo/p2 --
Missing position.
-- out/eval --
(_|_){
  // [eval]
  self: (struct){
    t1: (struct){
      a?: (int){ int }
    }
    t2: (struct){
      a!: (int){ int }
    }
  }
  unify: (struct){
    t1: (struct){
      p1: (struct){
        a: (int){ int }
      }
      p2: (struct){
        a: (int){ int }
      }
    }
    t2: (struct){
      p1: (struct){
        a!: (int){ int }
      }
      p2: (struct){
        a!: (int){ int }
      }
    }
  }
  #Def: (#struct){
    t1: (#struct){
      a!: (int){ int }
    }
  }
  allowed: (_|_){
    // [eval]
    issue2306: (_|_){
      // [eval]
      #A: (_|_){
        // [eval]
        a!: (_|_){
          // [eval] allowed.issue2306.#A.a: field not allowed:
          //     ./in.cue:34:6
          //     ./in.cue:35:6
          //     ./in.cue:37:6
        }
        b!: (int){ int }
      }
      #B: (#struct){
        b!: (int){ int }
      }
    }
  }
  reference: (struct){
    toWithinDefinition: (struct){
      p1: (struct){
        #Foo: (#struct){
          a!: (int){ int }
        }
        b: (int){ int }
      }
      p2: (struct){
        b: (int){ int }
        #Foo: (#struct){
          a!: (int){ int }
        }
      }
    }
    toFieldFromDefinition: (struct){
      p1: (struct){
        #Foo: (#struct){
          a!: (int){ int }
        }
        b: (#struct){
          a!: (int){ int }
        }
        c: (int){ int }
      }
      p2: (struct){
        c: (int){ int }
        b: (#struct){
          a!: (int){ int }
        }
        #Foo: (#struct){
          a!: (int){ int }
        }
      }
    }
    toNonDefinition: (struct){
      p1: (struct){
        x: (struct){
          y!: (_){ _ }
        }
        b: (_){ _ }
      }
      p2: (struct){
        b: (_){ _ }
        x: (struct){
          y!: (_){ _ }
        }
      }
    }
    toConcrete: (struct){
      p1: (struct){
        a!: (int){ 1 }
        b: (int){ 2 }
      }
      p2: (struct){
        b: (int){ 2 }
        a!: (int){ 1 }
      }
    }
  }
}
