diff options
| -rw-r--r-- | source/slang/check.cpp | 60 | ||||
| -rw-r--r-- | source/slang/diagnostic-defs.h | 1 | ||||
| -rw-r--r-- | tests/diagnostics/setter-method.slang | 23 | ||||
| -rw-r--r-- | tests/diagnostics/setter-method.slang.expected | 9 |
4 files changed, 92 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'") diff --git a/tests/diagnostics/setter-method.slang b/tests/diagnostics/setter-method.slang new file mode 100644 index 000000000..58e7c3417 --- /dev/null +++ b/tests/diagnostics/setter-method.slang @@ -0,0 +1,23 @@ +// setter-method.slang + +//TEST:SIMPLE: + +// Make sure we provide a user a diagnostic if they +// try to declare a setter method without `mutating` +// (even if we don't support `mutating` yet). + +struct Sphere +{ + float3 center; + float radius; + + void setCenter(float3 value) + { + center = value; + } + + void setRadius(float value) + { + this.radius = value; + } +}; diff --git a/tests/diagnostics/setter-method.slang.expected b/tests/diagnostics/setter-method.slang.expected new file mode 100644 index 000000000..237c499ee --- /dev/null +++ b/tests/diagnostics/setter-method.slang.expected @@ -0,0 +1,9 @@ +result code = -1 +standard error = { +tests/diagnostics/setter-method.slang(16): error 30011: left of '=' is not an l-value. +tests/diagnostics/setter-method.slang(16): note 30049: a 'this' parameter is currently immutable in Slang +tests/diagnostics/setter-method.slang(21): error 30011: left of '=' is not an l-value. +tests/diagnostics/setter-method.slang(21): note 30049: a 'this' parameter is currently immutable in Slang +} +standard output = { +} |
