summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/slang/check.cpp60
-rw-r--r--source/slang/diagnostic-defs.h1
2 files changed, 60 insertions, 1 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp
index 5fd8be2d5..6f9aa8adc 100644
--- a/source/slang/check.cpp
+++ b/source/slang/check.cpp
@@ -204,6 +204,19 @@ namespace Slang
expr->BaseExpression = baseExpr;
expr->name = declRef.GetName();
expr->declRef = declRef;
+
+ // When referring to a member through an expression,
+ // the result is only an l-value if both the base
+ // expression and the member agree that it should be.
+ //
+ // We have already used the `QualType` from the member
+ // above (that is `type`), so we need to take the
+ // l-value status of the base expression into account now.
+ if(!baseExpr->type.IsLeftValue)
+ {
+ expr->type.IsLeftValue = false;
+ }
+
return expr;
}
}
@@ -3991,6 +4004,46 @@ namespace Slang
else
{
getSink()->diagnose(expr, Diagnostics::assignNonLValue);
+
+ // As a special case, check if the LHS expression is derived
+ // from a `this` parameter (implicitly or explicitly), which
+ // is immutable. We can give the user a bit more context into
+ // what is going on.
+ //
+ // We will try to handle expressions of the form:
+ //
+ // e ::= "this"
+ // | e . name
+ // | e [ expr ]
+ //
+ // We will unwrap the `e.name` and `e[expr]` cases in a loop.
+ RefPtr<Expr> e = expr->left;
+ for(;;)
+ {
+ if(auto memberExpr = e.As<MemberExpr>())
+ {
+ e = memberExpr->BaseExpression;
+ }
+ else if(auto subscriptExpr = e.As<IndexExpr>())
+ {
+ e = subscriptExpr->BaseExpression;
+ }
+ else
+ {
+ break;
+ }
+ }
+ //
+ // Now we check to see if we have a `this` expression,
+ // and if it is immutable.
+ if(auto thisExpr = e.As<ThisExpr>())
+ {
+ if(!thisExpr->type.IsLeftValue)
+ {
+ getSink()->diagnose(thisExpr, Diagnostics::thisIsImmutableByDefault);
+ }
+ }
+
}
}
expr->type = type;
@@ -7800,7 +7853,12 @@ namespace Slang
{
QualType qualType;
qualType.type = GetType(varDeclRef);
- qualType.IsLeftValue = true; // TODO(tfoley): allow explicit `const` or `let` variables
+
+ bool isLValue = true;
+ if(varDeclRef.getDecl()->FindModifier<ConstModifier>())
+ isLValue = false;
+
+ qualType.IsLeftValue = isLValue;
return qualType;
}
else if (auto typeAliasDeclRef = declRef.As<TypeDefDecl>())
diff --git a/source/slang/diagnostic-defs.h b/source/slang/diagnostic-defs.h
index c77e75817..0dbacafe0 100644
--- a/source/slang/diagnostic-defs.h
+++ b/source/slang/diagnostic-defs.h
@@ -193,6 +193,7 @@ DIAGNOSTIC(30035, Error, componentOverloadTypeMismatch, "'$0': type of overloade
DIAGNOSTIC(30041, Error, bitOperationNonIntegral, "bit operation: operand must be integral type.")
DIAGNOSTIC(30047, Error, argumentExpectedLValue, "argument passed to parameter '$0' must be l-value.")
DIAGNOSTIC(30048, Note, implicitCastUsedAsLValue, "argument was implicitly cast from '$0' to '$1', and Slang does not support using an implicit cast as an l-value")
+DIAGNOSTIC(30049, Note, thisIsImmutableByDefault, "a 'this' parameter is currently immutable in Slang")
DIAGNOSTIC(30051, Error, invalidValueForArgument, "invalid value for argument '$0'")
DIAGNOSTIC(30052, Error, invalidSwizzleExpr, "invalid swizzle pattern '$0' on type '$1'")