Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistent behaviours of “coalesce” with “image” #9630

Closed
frodrigo opened this issue Apr 25, 2020 · 7 comments
Closed

Inconsistent behaviours of “coalesce” with “image” #9630

frodrigo opened this issue Apr 25, 2020 · 7 comments

Comments

@frodrigo
Copy link

According to the documentation, #8684 and #8052. “coalesce” should return the first existing “image”.

With last v1.9.1. Same behaviours on Firefox and Chrome.
https://js.do/code/432516

The style have icon for start_11 and oneway, but not for not_existing. Nevertheless, the flowing code return no icon.

    "icon-image": [
      "coalesce",
      ["image", "not_existing"],
      ["image", "star_11"]
    ],

The same code in text return not_existing:

    "text-field": [
      "string",
      [
        "coalesce",
        ["image", "not_existing"],
        ["image", "star_11"]
      ]
    ]

Playing more with coalesce give some “random” results

    "icon-image": [
      "coalesce",
      ["image", "not_existing"]
    ],
    "text-field": [
      "string",
      [
        "coalesce",
        ["image", "not_existing"]
      ]
    ]

Give unexpected not_existing (expected null)

    "icon-image": [
      "coalesce",
      ["image", "star_11"]
    ],
    "text-field": [
      "string",
      [
        "coalesce",
        ["image", "star_11"]
      ]
    ]

Give the star_11.

      "coalesce",
      ["image", "not_existing"],
      ["image", "star_11"],

Give unexpected not_existing (expected star_11)

      "coalesce",
      ["image", "star_11"],
      ["image", "not_existing"]

Give the star_11.

      "coalesce",
      ["image", "not_existing"],
      "star_11"

Give the star_11.

      "coalesce",
      ["image", "not_existing"],
      ["image", "star_11"],
      ["image", "oneway"]

Give unexpected not_existing (expected star_11)

      "coalesce",
      ["image", "not_existing"],
      ["image", "star_11"],
      "oneway"

Give unexpected oneway (expected star_11)

@arindam1993
Copy link
Contributor

Capturing internal convo,

@ryanhamley found the issue. It's a regression introduced with https://github.com/mapbox/mapbox-gl-js/pull/9352/files#diff-0856eb2171400e111b6a65dde5e0c789R76

since the canonical param was introduced in the middle of the function signature, it seems like certain places that call it place the data in the canonical param instead of availableImages.

@zmiao would you please be able to look at this? 🙏

@ryanhamley
Copy link
Contributor

ryanhamley commented Apr 27, 2020

@zmiao More specifically, this is where the bug reported in this demo is being caused. Changing this line to possiblyEvaluate(parameters, null, availableImages) fixes the immediate issue.

result._values[property] = this._values[property].possiblyEvaluate(parameters, availableImages);

This line looks like it has the same issue but I'm not exactly sure what conditions may trigger a bug here:

result._values[property] = this._values[property].possiblyEvaluate(parameters, availableImages);

I also see a similar signature here but again I'm not sure if/what bugs this can cause:

if (this._unevaluatedLayout) {
(this: any).layout = this._unevaluatedLayout.possiblyEvaluate(parameters, availableImages);
}
(this: any).paint = this._transitioningPaint.possiblyEvaluate(parameters, availableImages);

I think basically anywhere that evaluate or possiblyEvaluate is called without the canonical parameter before availableImages, this could be an issue.

I'd guess this could also break formatted usage since it also comes after the canonical arg but I haven't searched for instances of that.

#9198 probably also is broken. See this function:

function evaluateProperties(serializedProperties, styleLayerProperties, feature, featureState, availableImages) {
return mapObject(serializedProperties, (property, key) => {
const prop = styleLayerProperties instanceof PossiblyEvaluated ? styleLayerProperties.get(key) : null;
return prop && prop.evaluate ? prop.evaluate(feature, featureState, availableImages) : prop;
});
}

I'm not sure if it's better to just update a handful of signatures like this or if we should refactor canonical maybe to the end of the signature. This should have been caught in code review, but it was a large PR. I think maybe more unfortunate is that none of our tests caught this. The reason for that is that our expressions are tested in isolation rather than in a holistic manner within the map. This makes sense, but this bug shows that we have a blindspot in our testing.

@karimnaaji karimnaaji added this to the 0.10.1 milestone May 5, 2020
@karimnaaji
Copy link
Contributor

I'm not sure if it's better to just update a handful of signatures like this or if we should refactor canonical maybe to the end of the signature.

@ryanhamley Is there any way we could detect the code paths that require availableImages to be set? For example unwrap the parameters and assert if they are not complete in some of the above conditions?

I would also think that if these code paths worked before the regression without canonical we should be able to refactor and optionally add it at the end, availableImages does not seem to be optional. These are the cases that would be affected:

$ git grep "possiblyEvaluate(parameters,.*availableImages"
src/style/properties.js:        const finalValue = this.value.possiblyEvaluate(parameters, canonical, availableImages);
src/style/properties.js:            return prior.possiblyEvaluate(parameters, canonical, availableImages);
src/style/properties.js:            return this.property.interpolate(prior.possiblyEvaluate(parameters, canonical, availableImages), finalValue, easeCubicInOut(t));
src/style/properties.js:            result._values[property] = this._values[property].possiblyEvaluate(parameters, availableImages);
src/style/properties.js:            result._values[property] = this._values[property].possiblyEvaluate(parameters, availableImages);
src/style/style_layer.js:            (this: any).layout = this._unevaluatedLayout.possiblyEvaluate(parameters, availableImages);
src/style/style_layer.js:        (this: any).paint = this._transitioningPaint.possiblyEvaluate(parameters, availableImages);

@chloekraw
Copy link
Contributor

If our current theory about the root cause is correct, the regression was introduced in 1.9.0, so this should be patched into 1.9.x as well. I've created a milestone to help track that.

@chloekraw chloekraw modified the milestones: 1.10.1, 1.9.2 May 7, 2020
@chloekraw
Copy link
Contributor

Oh, nvm, an issue can't be on two milestones at once. 😛

@ryanhamley ryanhamley mentioned this issue May 8, 2020
9 tasks
@ryanhamley
Copy link
Contributor

We have a fix for this issue in #9668. Just working on a test and fixing Flow. This issue also helped uncover a second bug which is also fixed by #9668!

@ryanhamley
Copy link
Contributor

Closed by #9668

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants