Skip to content

Cycle Detection for Mixins

Mária Jurčovičová edited this page Sep 1, 2013 · 2 revisions

Mixins can lead into cycles:

.mixin {
  .mixin();
}

Detecting mixins cycles is harder then detecting variables cycles. Mixins can and do influence the state, so mixin can call itself without being in cycle:

.conditional(@a) {
  color: blue;
}

// mixin calls itself, but there is no cycle
.conditional(@a) when (@a > 10) {
  padding: @a;
  .conditional(@a - 1);
}

#usePlace {
  .conditional(13);
}

compiles into:

#usePlace {
  padding: 13;
  padding: 12;
  padding: 11;
  color: blue;
}

However, very similar less would cycle:

.conditional(@a) {
  color: blue;
}

// cycle
.conditional(@a) when (@a > 10) {
  padding: @a;
  .conditional(@a + 1);
}

#usePlace {
  .conditional(13);
}

In addition, each mixin has access to all variables defined in its caller, so all caller variables act like additional "hidden parameters":

.button() when (@a>10) {
  .button();
}

#maybeCycle {
  @a: 11; // causes stact overflow
  // @a: 2; // uncomment to remove stack overflow
 .button();
}

It is possible to detect cycles in some special situations e.g. if the cycle repeats the same state multiple times, but detecting them in all cases is NP-hard problem. Implemented cycle detection mechanism is explain on Other Compiler Features page.

Possible solution would be to detect unusually long mixins chains or measure memory and stop generation prior to stack overflow. We could then make some attempt to detect the cycle and print the most likely candidate.