diff --git a/README.md b/README.md
index f8b464b..2f358f6 100644
--- a/README.md
+++ b/README.md
@@ -51,23 +51,29 @@ For each `PathExpression` with a `VarHead` that is NOT in the local template sco
- If there is NO `tail`:
- - If the `MustacheStatement` is the child of an `AttrNode` with a name NOT starting with `@`:
+ - If the `MustacheStatement` is the child of an `AttrNode`
- Wrap the invocation with the `tryLookupHelper` helper to determine if it is a helper at runtime and fall back to the `this` property if not ("ambiguous attribute fallback").
+ - And the `AttrNode` represents a component argument (the name starts with `'@'`):
- ```hbs
- {{! before }}
-
+ Prefix the `head` with `this`, making it a `ThisHead` ("expression fallback"), as shown above.
- {{! after }}
- {{#let (hash property=(tryLookupHelper "property")) as |maybeHelpers|}}
-
- {{/let}}
- ```
+ - And the `AttrNode` represents an attribute (the name does not start with `'@'`):
+
+ Wrap the invocation with the `tryLookupHelper` helper to determine if it is a helper at runtime and fall back to the `this` property if not ("ambiguous attribute fallback").
+
+ ```hbs
+ {{! before }}
+
+
+ {{! after }}
+ {{#let (hash property=(tryLookupHelper "property")) as |maybeHelpers|}}
+
+ {{/let}}
+ ```
- Otherwise:
diff --git a/lib/this-fallback-plugin.ts b/lib/this-fallback-plugin.ts
index 03f8a15..f5805b3 100644
--- a/lib/this-fallback-plugin.ts
+++ b/lib/this-fallback-plugin.ts
@@ -92,7 +92,6 @@ class ThisFallbackPlugin implements ASTPlugin {
for (const attrNode of elementNode.attributes) {
const value = attrNode.value;
if (
- !attrNode.name.startsWith('@') &&
isNode(value, 'MustacheStatement') &&
mustacheNeedsFallback(value, this.scopeStack)
) {
@@ -101,11 +100,15 @@ class ThisFallbackPlugin implements ASTPlugin {
'attrNode.value is not a MustacheStatement',
isNode(attrNode.value, 'MustacheStatement')
);
- ambiguousHeads.set(value.path.head.name, value.loc);
- attrNode.value.path = helperOrExpressionFallback(
- blockParamName,
- value
- );
+ if (attrNode.name.startsWith('@')) {
+ attrNode.value.path = expressionFallback(value.path);
+ } else {
+ ambiguousHeads.set(value.path.head.name, value.loc);
+ attrNode.value.path = helperOrExpressionFallback(
+ blockParamName,
+ value
+ );
+ }
} else if (isNode(value, 'ConcatStatement')) {
for (const part of value.parts) {
const p = part;
@@ -182,8 +185,7 @@ class ThisFallbackPlugin implements ASTPlugin {
if (mustacheNeedsFallback(n, this.scopeStack)) {
assert(
'unexpected AmbiguousMustacheExpression in attribute value',
- path.parentNode?.type !== 'AttrNode' ||
- path.parentNode.name.startsWith('@')
+ path.parentNode?.type !== 'AttrNode'
);
if (n.path.tail.length > 0) {
node.path = expressionFallback(n.path);
diff --git a/tests/integration/plugin/mustache-statement-test.ts b/tests/integration/plugin/mustache-statement-test.ts
index 2896c00..66f8a92 100644
--- a/tests/integration/plugin/mustache-statement-test.ts
+++ b/tests/integration/plugin/mustache-statement-test.ts
@@ -86,6 +86,22 @@ module('Integration | Plugin | MustacheStatement', function (hooks) {
});
module('for an @arg', function () {
+ test('has this-fallback', async function (assert) {
+ this.set('property', 'property-on-this');
+ await render<{ property: string }>(hbs`
+ {{!--
+ @glint-expect-error:
+ Unknown name 'property' (Glint knows better than to let us do this)
+ --}}
+
+ {{yielded}}
+
+ `);
+ assert
+ .dom()
+ .hasText('global-component-contents property-on-this');
+ });
+
test('does nothing to ThisHead PathExpression', async function (assert) {
this.set('property', 'property-on-this');
await render<{ property: string }>(hbs`